diff --git a/jeepay-agent/pom.xml b/jeepay-agent/pom.xml new file mode 100644 index 0000000..44f934d --- /dev/null +++ b/jeepay-agent/pom.xml @@ -0,0 +1,185 @@ + + + 4.0.0 + + com.jeequan + jeepay-9219-agent + jar + ${isys.version} + Jeepay计全支付系统 [代理商后台管理端] + https://www.jeequan.com + + + com.jeequan + jeepay + Final + + + + + ${basedir}/../ + + + + + + + + com.jeequan + jeepay-components-db + + + + + com.jeequan + jeepay-components-3rd + + + + + com.jeequan + jeepay-components-oss + + + + + com.jeequan + jeepay-components-mq + + + + + com.jeequan + jeepay-components-bizcommons + + + + + org.springframework.boot + spring-boot-starter-web + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-parameter-names + + + org.hibernate.validator + hibernate-validator + + + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + io.jsonwebtoken + jjwt + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + com.jeequan + jeepay-sdk-java + + + + + org.springframework + spring-websocket + + + + + com.aliyun + aliyun-java-sdk-core + + + + + com.aliyun + aliyun-java-sdk-dysmsapi + + + + + com.google.zxing + core + + + com.google.zxing + javase + + + + + + + ${project.artifactId} + + + + + src/main/resources**/*.* + + + + ../conf/devCommons + **/*.yml + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + ${session.executionRootDirectory}/target/ + + + + + maven-resources-plugin + + + + + + + diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/aop/MethodLogAop.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/aop/MethodLogAop.java new file mode 100644 index 0000000..ddb4a6f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/aop/MethodLogAop.java @@ -0,0 +1,151 @@ +package com.jeequan.jeepay.agent.aop; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.db.entity.SysLog; +import com.jeequan.jeepay.service.impl.SysLogService; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** + * 方法级日志切面组件 + * + * @author terrfly + * @modify pangxiaoyu + * @date 2021-04-27 15:50 + */ +@Component +@Aspect +public class MethodLogAop{ + + private static final Logger logger = LoggerFactory.getLogger(MethodLogAop.class); + + @Autowired private SysLogService sysLogService; + + @Autowired private RequestKitBean requestKitBean; + + /** + * 异步处理线程池 + */ + private final static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10); + + /** + * 切点 + */ + @Pointcut("@annotation(com.jeequan.jeepay.core.aop.MethodLog)") + public void methodCachePointcut() { } + + /** + * 切面 + * @param point + * @return + * @throws Throwable + */ + @Around("methodCachePointcut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + + final SysLog sysLog = new SysLog(); + + //处理切面任务 发生异常将向外抛出 不记录日志 + Object result = point.proceed(); + + try { + // 基础日志信息 + setBaseLogInfo(point, sysLog, JeeUserDetails.getCurrentUserDetails()); + sysLog.setOptResInfo(JSON.toJSON(result).toString()); + scheduledThreadPool.execute(() -> sysLogService.save(sysLog)); + } catch (Exception e) { + logger.error("methodLogError", e); + } + + return result; + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 14:04 + * @describe: 记录异常操作请求信息 + */ + @AfterThrowing(pointcut = "methodCachePointcut()", throwing="e") + public void doException(JoinPoint joinPoint, Throwable e) throws Exception{ + final SysLog sysLog = new SysLog(); + // 基础日志信息 + setBaseLogInfo(joinPoint, sysLog, JeeUserDetails.getCurrentUserDetails()); + sysLog.setOptResInfo(e instanceof BizException ? e.getMessage() : "请求异常"); + scheduledThreadPool.execute(() -> sysLogService.save(sysLog)); + } + + /** + * 获取方法中的中文备注 + * @param joinPoint + * @return + * @throws Exception + */ + public static String getAnnotationRemark(JoinPoint joinPoint) throws Exception { + + Signature sig = joinPoint.getSignature(); + Method m = joinPoint.getTarget().getClass().getMethod(joinPoint.getSignature().getName(), ((MethodSignature) sig).getParameterTypes()); + + MethodLog methodCache = m.getAnnotation(MethodLog.class); + if (methodCache != null) { + return methodCache.remark(); + } + return ""; + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 14:12 + * @describe: 日志基本信息 公共方法 + */ + private void setBaseLogInfo(JoinPoint joinPoint, SysLog sysLog, JeeUserDetails userDetails) throws Exception { + // 使用point.getArgs()可获取request,仅限于spring MVC参数包含request,改为通过contextHolder获取。 + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + + //请求参数 + sysLog.setOptReqParam( requestKitBean.getReqParamJSON().toJSONString() ); + + //注解备注 + sysLog.setMethodRemark(getAnnotationRemark(joinPoint)); + //包名 方法名 + String methodName = joinPoint.getSignature().getName(); + String packageName = joinPoint.getThis().getClass().getName(); + if (packageName.indexOf("$$EnhancerByCGLIB$$") > -1 || packageName.indexOf("$$EnhancerBySpringCGLIB$$") > -1) { // 如果是CGLIB动态生成的类 + packageName = packageName.substring(0, packageName.indexOf("$$")); + } + sysLog.setMethodName(packageName + "." + methodName); + sysLog.setReqUrl(request.getRequestURL().toString()); + sysLog.setUserIp(requestKitBean.getClientIp()); + sysLog.setCreatedAt(new Date()); + sysLog.setSysType(CS.SYS_ROLE_TYPE.AGENT); + + if (userDetails != null) { + sysLog.setUserId(JeeUserDetails.getCurrentUserDetails().getSysUser().getSysUserId()); + sysLog.setUserName(JeeUserDetails.getCurrentUserDetails().getSysUser().getRealname()); + sysLog.setSysType(JeeUserDetails.getCurrentUserDetails().getSysUser().getSysType()); + } + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/InitRunner.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/InitRunner.java new file mode 100644 index 0000000..65a6e88 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/InitRunner.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.agent.bootstrap; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.crypto.SmUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializeConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer; +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * 项目初始化操作 + * 比如初始化配置文件, 读取基础数据, 资源初始化等。 避免在Main函数中写业务代码。 + * CommandLineRunner / ApplicationRunner都可以达到要求, 只是调用参数有所不同。 + * + * @author terrfly + * + * @date 2021-04-27 15:50 + */ +@Component +public class InitRunner implements CommandLineRunner { + + @Autowired private SystemYmlConfig systemYmlConfig; + @Autowired private SysConfigService sysConfigService; + + + @Override + public void run(String... args) throws Exception { + + // 配置是否使用缓存模式 + SysConfigService.IS_USE_CACHE = systemYmlConfig.getCacheConfig(); + + // 初始化系统秘钥 + SysConfigService.DB_ENCRYPT_SECRET = systemYmlConfig.getDbEncryptSecret(); + SysConfigService.DB_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.DB_ENCRYPT_SECRET.getBytes()); + SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET = systemYmlConfig.getHttpMessageEncryptSecret(); + SysConfigService.HTTP_MESSAGE_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.HTTP_MESSAGE_ENCRYPT_SECRET.getBytes()); + + // 支持服务商 + SysConfigService.IS_HAS_AGENT_ENT = true; + + // 检查是否支持会员 + SysConfigService.IS_HAS_MEMBER_ENT = sysConfigService.getById(SysConfigService.MEMBER_ENT_CONFIG) != null; + + // 配置是否通信加密 和 密码修改 + SysConfigService.HTTP_MSG_IS_ENCRYPT = sysConfigService.getDBSecurityConfig().httpMsgIsEncrypt(); + SysConfigService.PWD_EXPIRED_MUST_RESET = sysConfigService.getDBSecurityConfig().passwordExpiredIsMustModify(); + + // 配置 平台通信秘钥 + SysConfigService.PLATFORM_API_SECRET = sysConfigService.getDBSecurityConfig().getPlatformApiSecret(); + + //初始化处理fastjson格式 + SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance(); + serializeConfig.put(Date.class, new SimpleDateFormatSerializer(DatePattern.NORM_DATETIME_PATTERN)); + + //解决json 序列化时候的 $ref:问题 + JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask(); + + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/JeepayAgentApplication.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/JeepayAgentApplication.java new file mode 100644 index 0000000..4b31a30 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/bootstrap/JeepayAgentApplication.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.agent.bootstrap; + +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Arrays; + +/** + * spring-boot 主启动程序 + * + * @author terrfly + * + * @date 2022-03-14 08:50 + */ +@SpringBootApplication +@EnableScheduling +@MapperScan("com.jeequan.jeepay.service.mapper") //Mybatis mapper接口路径 +@ComponentScan(basePackages = "com.jeequan.jeepay.*") //由于MainApplication没有在项目根目录, 需要配置basePackages属性使得成功扫描所有Spring组件; +@Configuration +public class JeepayAgentApplication { + + /** main启动函数 **/ + public static void main(String[] args) { + + //启动项目 + SpringApplication.run(JeepayAgentApplication.class, args); + + } + + /** 支持搜索 {} [] 否则 springboot 提示 HTTP Status 400 – Bad Request **/ + @Bean + public TomcatServletWebServerFactory tomcatServletWebServerFactory (){ + // 修改内置的 tomcat 容器配置 + TomcatServletWebServerFactory tomcatServlet = new TomcatServletWebServerFactory(); + tomcatServlet.addConnectorCustomizers( connector -> connector.setProperty("relaxedQueryChars", "[]{}") ); + return tomcatServlet ; + } + + /** fastJson 配置信息 **/ + @Bean + public HttpMessageConverters fastJsonConfig(){ + + // 开启 FastJSON 安全模式! + ParserConfig.getGlobalInstance().setSafeMode(true); + + //新建fast-json转换器 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); + + //fast-json 配置信息 + FastJsonConfig config = new FastJsonConfig(); + config.setDateFormat("yyyy-MM-dd HH:mm:ss"); + converter.setFastJsonConfig(config); + + //设置响应的 Content-Type + converter.setSupportedMediaTypes(Arrays.asList(new MediaType[]{MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8})); + return new HttpMessageConverters(converter); + } + + /** Mybatis plus 分页插件 **/ + @Bean + public MybatisPlusInterceptor paginationInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false + // paginationInterceptor.setOverflow(false); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; + } + + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/RedisConfig.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/RedisConfig.java new file mode 100644 index 0000000..24e059a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/RedisConfig.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.agent.config; + +import com.jeequan.jeepay.core.cache.RedisUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * redis管理类 + * + * @author terrfly + * + * @date 2021-04-27 15:50 + */ +@Configuration +public class RedisConfig { + + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.port}") + private Integer port; + + @Value("${spring.redis.timeout}") + private Integer timeout; + + @Value("${spring.redis.database}") + private Integer defaultDatabase; + + @Value("${spring.redis.password}") + private String password; + + /** 作用:不同系统的前缀。 a.当连接不同的database时可以为空(物理隔离); b.当redis集群时因为必须同一个database,所以需通过前缀区分不同系统的业务。 **/ + @Value("${spring.redis.sys-prefix-key}") + private String sysPrefixKey; + + /** 当前系统的redis缓存操作对象 (主对象) **/ + @Primary + @Bean(name = "defaultStringRedisTemplate") + public StringRedisTemplate sysStringRedisTemplate() { + + // 赋值前缀key + RedisUtil.SYS_PREFIX_KEY = sysPrefixKey; + + StringRedisTemplate template = new StringRedisTemplate(); + + LettuceConnectionFactory jedisConnectionFactory = new LettuceConnectionFactory(); + jedisConnectionFactory.setHostName(host); + jedisConnectionFactory.setPort(port); + jedisConnectionFactory.setTimeout(timeout); + + if (!StringUtils.isEmpty(password)) { + jedisConnectionFactory.setPassword(password); + } + + if (defaultDatabase != 0) { + jedisConnectionFactory.setDatabase(defaultDatabase); + } + + jedisConnectionFactory.afterPropertiesSet(); + + template.setConnectionFactory(jedisConnectionFactory); + return template; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/SystemYmlConfig.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/SystemYmlConfig.java new file mode 100644 index 0000000..3ebe3c8 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/config/SystemYmlConfig.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.agent.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 系统Yml配置参数定义Bean + * + * @author terrfly + * + * @date 2021-04-27 15:50 + */ +@Component +@ConfigurationProperties(prefix="isys") +@Data +public class SystemYmlConfig { + + /** 是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] **/ + private Boolean allowCors; + + /** 生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。 **/ + private String jwtSecret; + + /** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/ + private String dbEncryptSecret; + + /** web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/ + private String httpMessageEncryptSecret; + + /** 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/ + private String sysRSA2PrivateKey; + + /**支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! **/ + private String sysRSA2PublicKey; + + /** 是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. **/ + private Boolean cacheConfig; + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CommonCtrl.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CommonCtrl.java new file mode 100644 index 0000000..6c5e66d --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CommonCtrl.java @@ -0,0 +1,225 @@ +package com.jeequan.jeepay.agent.ctrl; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.ctrls.AbstractCtrl; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.BaseModel; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchStore; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 通用ctrl类 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +public abstract class CommonCtrl extends AbstractCtrl { + + @Autowired protected SystemYmlConfig mainConfig; + + @Autowired protected SysConfigService sysConfigService; + + @Autowired protected MchInfoService mchInfoService; + + @Autowired protected MchStoreService mchStoreService; + + @Autowired protected PayInterfaceDefineService payInterfaceDefineService; + + @Autowired protected AgentInfoService agentInfoService; + + /** 获取当前用户ID */ + protected JeeUserDetails getCurrentUser(){ + + return (JeeUserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + /** 获取当前商户ID **/ + protected String getCurrentAgentNo() { + return getCurrentUser().getSysUser().getBelongInfoId(); + } + + /** + * 获取当前用户登录IP + * @return + */ + protected String getIp() { + return getClientIp(); + } + + /** + * 校验当前用户是否为超管 + * @return + */ + protected ApiRes checkIsAdmin() { + SysUser sysUser = getCurrentUser().getSysUser(); + if (sysUser.getUserType() != SysUser.UEST_TYPE_ADMIN) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + }else { + return null; + } + + } + + /** model 存入服务商名称 **/ + public void setAgentName(List modeList) { + + if(modeList == null || modeList.isEmpty()){ + return ; + } + ArrayList agentNoList = new ArrayList<>(); + for (BaseModel model:modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String agentNo = json.getString("agentNo"); + agentNoList.add(agentNo); + } + List agentInfoList = agentInfoService.list(AgentInfo.gw().select(AgentInfo::getAgentNo, AgentInfo::getAgentName).in(AgentInfo::getAgentNo, agentNoList)); + for (BaseModel model:modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String agentNo = json.getString("agentNo"); + + if(StringUtils.isBlank(agentNo)) { + continue; + } + + for (AgentInfo info:agentInfoList) { + if (agentNo.equals(info.getAgentNo())) { + model.addExt("agentName", info.getAgentName()); + } + } + } + } + + /** model 存入商户名称 **/ + public void setMchName(List modeList) { + + if(modeList == null || modeList.isEmpty()){ + return ; + } + ArrayList mchNoList = new ArrayList<>(); + for (BaseModel model:modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String mchNo = json.getString("mchNo"); + mchNoList.add(mchNo); + } + List mchInfoList = mchInfoService.list(MchInfo.gw().select(MchInfo::getMchNo, MchInfo::getMchName).in(MchInfo::getMchNo, mchNoList)); + for (BaseModel model:modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String mchNo = json.getString("mchNo"); + + if(StringUtils.isBlank(mchNo)) { + continue; + } + + for (MchInfo info:mchInfoList) { + if (mchNo.equals(info.getMchNo())) { + model.addExt("mchName", info.getMchName()); + } + } + } + } + + /** model 存入门店名称 **/ + public void setStoreName(List modeList) { + + if (modeList == null || modeList.isEmpty()) { + return; + } + ArrayList storeIdList = new ArrayList<>(); + for (BaseModel model : modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String storeId = json.getString("storeId"); + storeIdList.add(storeId); + } + List mchInfoList = mchStoreService.list(MchStore.gw().select(MchStore::getStoreId, MchStore::getStoreName).in(MchStore::getStoreId, storeIdList)); + for (BaseModel model : modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String storeId = json.getString("storeId"); + + if (storeId == null) { + continue; + } + + for (MchStore store : mchInfoList) { + if (storeId.equals(store.getStoreId())) { + model.addExt("storeName", store.getStoreName()); + } + } + } + } + + /** model 存入支付接口名称 **/ + public void setIfName(List modeList) { + + if(modeList == null || modeList.isEmpty()){ + return ; + } + ArrayList ifCodeList = new ArrayList<>(); + for (BaseModel model:modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String ifCode = json.getString("ifCode"); + ifCodeList.add(ifCode); + } + List defineList = payInterfaceDefineService.list(PayInterfaceDefine.gw().select(PayInterfaceDefine::getIfCode, PayInterfaceDefine::getIfName).in(PayInterfaceDefine::getIfCode, ifCodeList)); + for (BaseModel model : modeList) { + JSONObject json = (JSONObject) JSONObject.toJSON(model); + String ifCode = json.getString("ifCode"); + + if(StringUtils.isBlank(ifCode)) { + continue; + } + + for (PayInterfaceDefine define : defineList) { + if (ifCode.equals(define.getIfCode())) { + model.addExt("ifName", define.getIfName()); + } + } + } + } + + /** 判断当前用户是否有某个权限 */ + public boolean currentUserHasEnt(String ent){ + return getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_MCH_APPLYMENT_PAY_CONFIG")); + } + + /** 根据服务商号,查询服务商下的商户号List **/ + public List getMchNoListByAgentNo(String agentNo) { + + if (StringUtils.isBlank(agentNo)) { + return null; + } + + AgentInfo agentInfo = agentInfoService.getById(agentNo); + if (agentInfo == null || agentInfo.getState() != CS.YES) { + throw new BizException("服务商不存在或状态不正确"); + } + + List list = mchInfoService.list(MchInfo.gw().eq(com.jeequan.jeepay.core.entity.MchInfo::getAgentNo, agentNo)); + if (CollUtil.isEmpty(list)) { + return null; + } + + List mchNoList = new LinkedList<>(); + list.forEach(mchInfo -> mchNoList.add(mchInfo.getMchNo())); + return mchNoList; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CurrentUserController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CurrentUserController.java new file mode 100644 index 0000000..11f935f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/CurrentUserController.java @@ -0,0 +1,267 @@ +package com.jeequan.jeepay.agent.ctrl; + +import cn.hutool.core.codec.Base64; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.bizcommons.manage.auth.AuthByQrcodeManage; +import com.jeequan.jeepay.converter.BaseConverter; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.cache.ITokenService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.core.utils.TreeDataBuilder; +import com.jeequan.jeepay.core.utils.google.GoogleAuth; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.SysEntitlement; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 当前登录者的信息相关接口 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/current") +public class CurrentUserController extends CommonCtrl{ + + @Autowired private SysEntitlementService sysEntitlementService; + @Autowired private SysUserService sysUserService; + @Autowired private SysUserAuthService sysUserAuthService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private BaseConverter baseConverter; + + @RequestMapping(value="/user", method = RequestMethod.GET) + public ApiRes currentUserInfo() { + + ///当前用户信息 + JeeUserDetails jeeUserDetails = getCurrentUser(); + SysUserEntity user = sysUserService.getById(jeeUserDetails.getSysUser().getSysUserId()); + + //1. 当前用户所有权限ID集合 + List entIdList = new ArrayList<>(); + jeeUserDetails.getAuthorities().forEach(r->entIdList.add(r.getAuthority())); + + List allMenuList = new ArrayList<>(); //所有菜单集合 + + //2. 查询出用户所有菜单集合 (包含左侧显示菜单 和 其他类型菜单 ) + if(!entIdList.isEmpty()){ + allMenuList = sysEntitlementService.list(SysEntitlement.gw() + .in(SysEntitlement::getEntId, entIdList) + .in(SysEntitlement::getEntType, Arrays.asList(CS.ENT_TYPE.MENU_LEFT, CS.ENT_TYPE.MENU_OTHER)) + .eq(SysEntitlement::getSysType, CS.SYS_ROLE_TYPE.AGENT) + .eq(SysEntitlement::getState, CS.PUB_USABLE)); + } + + //4. 转换为json树状结构 + JSONArray jsonArray = (JSONArray) JSON.toJSON(allMenuList); + List allMenuRouteTree = new TreeDataBuilder(jsonArray, + "entId", "pid", "children", "entSort", true) + .buildTreeObject(); + + //5. 所有权限ID集合 + user.addExt("entIdList", entIdList); + user.addExt("allMenuRouteTree", allMenuRouteTree); + user.addExt("mchType", jeeUserDetails.getMchType()); + //6. 获取服务商简称 + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + user.addExt("shortName",agentInfo.getAgentShortName()); + + // 7. 程序是否支持会员 + user.addExt("isHasMemberEnt", SysConfigService.IS_HAS_MEMBER_ENT); + + //8.获取邀请码链接信息 商户注册 + if (StringUtils.isNotEmpty(user.getInviteCode())) { + // 邀请码二维码地址 + String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl()); + user.addExt("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, user.getInviteCode())); + } + + if (StringUtils.isNotEmpty(user.getInviteCode())) { + // 服务商邀请码二维码地址 + String agtRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getAgentSiteUrl()); + user.addExt("agtInviteCodeUrl", String.format("%s?c=%s", agtRegisterUrl, user.getInviteCode())); + } + + return ApiRes.ok(user); + } + + + /** 修改个人信息 */ + @MethodLog(remark = "修改个人信息") + @RequestMapping(value="/user", method = RequestMethod.PUT) + public ApiRes modifyCurrentUserInfo() { + + //修改头像 + String avatarUrl = getValString("avatarUrl"); + String realname = getValString("realname"); + Byte sex = getValByte("sex"); + //编辑预留信息 + String safeWord = getValString("safeWord"); + SysUserEntity updateRecord = new SysUserEntity(); + updateRecord.setSysUserId(getCurrentUser().getSysUser().getSysUserId()); + if (StringUtils.isNotEmpty(avatarUrl)) { + updateRecord.setAvatarUrl(avatarUrl); + } + if (StringUtils.isNotEmpty(realname)) { + updateRecord.setRealname(realname); + } + if (sex != null) { + updateRecord.setSex(sex); + } + if (StringUtils.isNotEmpty(safeWord)) { + updateRecord.setSafeWord(safeWord); + } + sysUserService.updateById(updateRecord); + + + //保存redis最新数据 + JeeUserDetails currentUser = getCurrentUser(); + SysUserEntity sysUserEntity = sysUserService.getById(getCurrentUser().getSysUser().getSysUserId()); + currentUser.setSysUser(baseConverter.toModel(sysUserEntity)); + ITokenService.refData(currentUser); + + return ApiRes.ok(); + } + + + /** modifyPwd */ + @MethodLog(remark = "修改密码") + @RequestMapping(value="modifyPwd", method = RequestMethod.PUT) + public ApiRes modifyPwd() throws BizException{ + + Long opSysUserId = getCurrentUser().getSysUser().getSysUserId(); + + //更改密码,验证当前用户信息 + String currentUserPwd = Base64.decodeStr(getValStringRequired("originalPwd")); //当前用户登录密码 + //验证当前密码是否正确 + if(!sysUserAuthService.validateCurrentUserPwd(currentUserPwd)){ + throw new BizException("原密码验证失败!"); + } + + String opUserPwd = Base64.decodeStr(getValStringRequired("confirmPwd")); + + // 验证原密码与新密码是否相同 + if (opUserPwd.equals(currentUserPwd)) { + throw new BizException("新密码与原密码不能相同!"); + } + + sysUserAuthService.resetAuthInfo(opSysUserId, null, null, true, opUserPwd, CS.SYS_ROLE_TYPE.AGENT); + //调用登出接口 + return logout(); + } + + /** 登出 */ + @MethodLog(remark = "退出") + @RequestMapping(value="logout", method = RequestMethod.POST) + public ApiRes logout() throws BizException{ + + ITokenService.removeIToken(getCurrentUser().getCacheKey(), getCurrentUser().getSysUser().getSysUserId()); + return ApiRes.ok(); + } + + /** MFA验证信息 */ + @GetMapping("/mfaInfo") + @MethodLog(remark = "MFA验证信息") + public ApiRes mfaInfo() throws BizException{ + SysUserEntity currentUser = sysUserService.getById(getCurrentUser().getSysUserId()); + JSONObject resJson = new JSONObject(); + resJson.put("mfaBindState", currentUser.getMfaBindState()); + resJson.put("telPhone", currentUser.getTelphone()); + // 是否展示MFA绑定信息 [未绑定时显示] + if (currentUser.getMfaBindState() == CS.NO) { + String secretKey = sysUserService.getById(currentUser.getSysUserId()).getMfaSecretKey(); + // 更新用户验证秘钥 + if (StringUtils.isEmpty(secretKey)) { + secretKey = GoogleAuth.generateSecretKey(); + sysUserService.updateMFASecret(currentUser.getSysUserId(), secretKey, null); + } + String qrcodeUrl = GoogleAuth.getQRBarcode( + sysConfigService.getOemConfig().getSysName() + "_服务商" +"("+ currentUser.getTelphone() + ")" + , secretKey); + resJson.put("mfaBindUrl", qrcodeUrl); + resJson.put("mfaSecretKey", secretKey); + } + return ApiRes.ok(resJson); + } + + /** MFA验证 绑定 */ + @RequestMapping(value="mfaBind", method = RequestMethod.PUT) + @MethodLog(remark = "MFA验证绑定") + public ApiRes mfaBind() throws BizException{ + String verCode = getValStringRequired("verCode"); + Long userId = getCurrentUser().getSysUserId(); + // 验证验证码 + sysUserService.checkMFACode(userId, verCode); + + // 绑定MFA验证 + sysUserService.bindMFA(userId); + return ApiRes.ok(); + } + + /** MFA验证 解绑 */ + @RequestMapping(value="mfaRelieve", method = RequestMethod.PUT) + @MethodLog(remark = "MFA验证解除") + public ApiRes mfaRelieve() throws BizException{ + String verCode = getValStringRequired("verCode"); + Long userId = getCurrentUser().getSysUserId(); + // 验证验证码 + sysUserService.checkMFACode(userId, verCode); + + // 解除MFA验证 + sysUserService.relieveMFA(userId, CS.SYS_ROLE_TYPE.AGENT); + return ApiRes.ok(); + } + + + /** app扫码登录接口 */ + @PostMapping("qrcode/login") + public ApiRes loginQrcodeConfirm(){ + + String qrcodeNo = getValStringRequired("qrcodeNo"); + String qrCodeStatus = getValStringRequired("qrcodeStatus"); + + if (!StringUtils.equalsAny(qrCodeStatus, AuthByQrcodeManage.QRCODE_STATUS_SCANED, AuthByQrcodeManage.QRCODE_STATUS_CANCELED, + AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED)) { + return ApiRes.customFail("二维码错误"); + } + + // 更新状态:等待扫码 --> 已扫 + if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_SCANED)) { + + AuthByQrcodeManage.updateQrcodeStatusWaiting2Scaned(qrcodeNo); + return ApiRes.ok(); + + // 更新状态:已扫 --> 取消 + }else if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_CANCELED)) { + + AuthByQrcodeManage.updateQrcodeStatusScaned2Canceled(CS.SYS_ROLE_TYPE.AGENT, qrcodeNo); + return ApiRes.ok(); + + } + + // 更新状态:已扫 --> 确认登录 + JSONObject tokenJSON = SpringBeansUtil.getBean(AuthService.class).authByAppQrcode(getCurrentUser().getSysUserId(), JWTPayload.LOGIN_PAGE_TYPE.WEB); + + // 更新状态:已扫 --> 确认登录 + AuthByQrcodeManage.updateQrcodeStatusScaned2Confirmed(qrcodeNo, tokenJSON.toJSONString()); + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/StatController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/StatController.java new file mode 100644 index 0000000..82efe20 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/StatController.java @@ -0,0 +1,239 @@ +package com.jeequan.jeepay.agent.ctrl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 统计相关接口 + * + * @author terrfly + * @date 2022-03-16 15:50 + */ +@RestController +@RequestMapping("/api/stat") +public class StatController extends CommonCtrl{ + + @Autowired private InfoAccountService infoAccountService; + @Autowired private MchInfoService mchInfoService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private PayOrderService payOrderService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private SysUserService sysUserService; + @Autowired private MchQrcodeCardService mchQrcodeCardService; + + /** 统计数据 **/ + @PreAuthorize("hasAnyAuthority('ENT_C_MAIN_AGENT_COUNT', 'ENT_AGENT_STATISTIC_COUNT')") + @RequestMapping(value="/index", method = RequestMethod.GET) + public ApiRes currentUserInfo() { + + JSONObject paramJSON = getReqParamJSON(); + String agentNo = null; + List agentSubList = null; + + // 统计数据类型countType: 1-服务商本身数据 2-我与全部下级服务商数据 3-服务商号搜索 + Byte countType = paramJSON.getByte("countType"); + if (countType != null && countType == 2) { + agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + } else if (countType != null && countType == 3) { + agentNo = getValStringRequired("agentNo"); + }else { + agentNo = getCurrentAgentNo(); + } + + // 拓展员参数 + if (getCurrentUser().isEpUser()) { + paramJSON.put("epUserId", getCurrentUser().getSysUser().getSysUserId()); + } + + // 1. 钱包余额 + InfoAccount infoAccount = infoAccountService.queryById(agentNo, CS.SYS_ROLE_TYPE.AGENT); + + JSONObject result = new JSONObject(); + result.put("realBalanceAmount", infoAccount == null ? 0L : infoAccount.getBalanceAmount()); + result.put("unAmount", infoAccount == null ? 0L : infoAccount.getUnAmount()); + result.put("auditProfitAmount", infoAccount == null ? 0L : infoAccount.getAuditProfitAmount()); + // 页面上的钱包余额 + Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount(); + result.put("availableBalanceAmount", availableBalanceAmount); + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + // 冻结金额 及 冻结原因 + Long freezeAmount = agentInfo == null ? 0L : agentInfo.getFreezeAmount(); + result.put("freezeAmount", freezeAmount); + result.put("freezeDesc", agentInfo == null ? "" : agentInfo.getFreezeDesc()); + // 可提现金额(页面上的钱包余额-冻结金额) + result.put("allowTakeAmount", Math.max(availableBalanceAmount - freezeAmount, 0L)); + + JSONObject mchJson = mchInfoService.mchCount(agentNo, agentSubList, paramJSON); + result.put("mchCount", mchJson); + + JSONObject agentJson = agentInfoService.agentCount(agentNo, agentSubList, paramJSON); + result.put("agentCount", agentJson); + + // 日交易统计 + String mchNo = paramJSON.getString("mchNo"); + Map countMap = payOrderService.tradeCount(mchNo, agentNo, agentSubList, paramJSON); + + // 订单统计 + result.put("orderCount", countMap); + + // 今日交易笔数 + result.put("orderTodayCount", countMap.get("payCount")); + + // 今日交易金额 + result.put("orderTodaySum", countMap.get("payAmount")); + // 码牌总数 + long qrCodeCardAllCount = mchQrcodeCardService.count( + MchQrcodeCard.gw() + .eq(MchQrcodeCard::getAgentNo, getCurrentAgentNo()) + .eq(MchQrcodeCard::getQrcState, CS.YES)); + result.put("qrCodeCardAllCount", qrCodeCardAllCount); + // 已绑定的码牌 + long qrCodeCardBindCount = mchQrcodeCardService.count( + MchQrcodeCard.gw() + .eq(MchQrcodeCard::getAgentNo, getCurrentAgentNo()) + .eq(MchQrcodeCard::getQrcState, CS.YES) + .eq(MchQrcodeCard::getBindState, CS.YES)); + result.put("qrCodeCardBindCount", qrCodeCardBindCount); + // 剩余空码 + result.put("qrCodeCardUnBindCount", qrCodeCardAllCount - qrCodeCardBindCount); + + // 云喇叭总数 + long speakerAllCount = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_SPEAKER) + ); + result.put("speakerAllCount", speakerAllCount); + // 未绑定喇叭数 + long speakerUnCount = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_SPEAKER) + .eq(MchStoreDevice::getBindState, CS.NO) + ); + result.put("speakerUnCount", speakerUnCount); + // 云打印总数 + long printerAllCount = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_PRINTER) + ); + result.put("printerAllCount", printerAllCount); + // 未绑定打印数 + long printerUnCount = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_PRINTER) + .eq(MchStoreDevice::getBindState, CS.NO) + ); + result.put("printerUnCount", printerUnCount); + // 扫码pos机总数 + result.put("posAllCount", mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_POS) + )); + // 未绑定扫码pos数 + result.put("posUnCount", mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_POS) + .eq(MchStoreDevice::getBindState, CS.NO) + )); + // 智能pos机总数 + result.put("posAllCount", mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_AUTO_POS) + )); + // 未绑定智能pos数 + result.put("posUnCount", mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAgentNo, getCurrentAgentNo()) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_AUTO_POS) + .eq(MchStoreDevice::getBindState, CS.NO) + )); + + return ApiRes.ok(result); + } + + /** + * @author: xiaoyu + * @date: 2022/3/23 16:39 + * @describe: 拓展员商户统计数据 + */ + @RequestMapping(value="/userChart", method = RequestMethod.GET) + public ApiRes userChart() { + + Long sysUserId = getValLongRequired("sysUserId"); + String dateRange = getValString("queryDateRange"); + + SysUserEntity sysUserEntity = sysUserService.getById(sysUserId); + if (sysUserEntity == null || !sysUserEntity.getBelongInfoId().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 返回数据 + JSONObject result = new JSONObject(); + result.put("mchAllCount", 0); + result.put("mchTodayAddCount", 0); + result.put("mchOnNetCount", 0); + result.put("mchOnNetNewCount", 0); + result.put("payAllAmount", 0); + result.put("payAmount", 0); + + // 拓展员邀请的商户 + List list = mchInfoService.list(MchInfo.gw().eq(MchInfo::getCreatedUid, sysUserId)); + if (CollUtil.isEmpty(list)) { + return ApiRes.ok(result); + } + + String createdStart = null; + String createdEnd = null; + if (StringUtils.isNotEmpty(dateRange)) { + // 获取查询时间请求参数 [开始时间, 结束时间] + Date[] queryDateRangeArray = DateKit.getQueryDateRange(dateRange); + + createdStart = DateUtil.formatDateTime(queryDateRangeArray[0]); + createdEnd = DateUtil.formatDateTime(queryDateRangeArray[1]); + } + + + // 商户总数 + long mchAllCount = mchInfoService.mchCount(null, sysUserId, createdStart, createdEnd); + result.put("mchAllCount", mchAllCount); + + // 按时间搜索商户数 + long mchTodayAddCount = mchInfoService.mchCount(null, sysUserId, createdStart, createdEnd); + result.put("mchTodayAddCount", mchTodayAddCount); + + // 商户入网总数 + long mchOnNetCount = mchInfoService.mchApplyCount(null, sysUserId, createdStart, createdEnd); + result.put("mchOnNetCount", mchOnNetCount); + + // 按时间搜索商户入网数 + long mchOnNetNewCount = mchInfoService.mchApplyCount(null, sysUserId, createdStart, createdEnd); + result.put("mchOnNetNewCount", mchOnNetNewCount); + + BigDecimal payAllAmount = payOrderService.totalAmount(null, sysUserId, createdStart, createdEnd); + result.put("payAllAmount", payAllAmount); + + BigDecimal payAmount = payOrderService.totalAmount(null, sysUserId, createdStart, createdEnd); + result.put("payAmount", payAmount); + + return ApiRes.ok(result); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/AccountChangeInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/AccountChangeInfoController.java new file mode 100644 index 0000000..4d14d2b --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/AccountChangeInfoController.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.agent.ctrl.account; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.AccountChangeInfo; +import com.jeequan.jeepay.service.impl.AccountChangeInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * TODO + * + * @author crystal + * @date 2023/12/6 15:11 + */ +@RestController +@RequestMapping("/api/accountChange") +public class AccountChangeInfoController extends CommonCtrl { + + @Autowired private AccountChangeInfoService accountChangeInfoService; + + @PreAuthorize("hasAuthority('ENT_ACCOUNT_CHANGE_LIST')") + @GetMapping + public ApiRes list() { + AccountChangeInfo info = getObject(AccountChangeInfo.class); + JSONObject paramJSON = getReqParamJSON(); + LambdaQueryWrapper wrapper = AccountChangeInfo.gw(info); + Page pages = accountChangeInfoService.pageList(getIPage(),wrapper,info,paramJSON); + return ApiRes.page(pages); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/CashoutRecordController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/CashoutRecordController.java new file mode 100644 index 0000000..02cc5d2 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/CashoutRecordController.java @@ -0,0 +1,259 @@ +package com.jeequan.jeepay.agent.ctrl.account; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.DesensitizedUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.applyment.CashoutFee; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.CashoutRecord; +import com.jeequan.jeepay.db.entity.InfoAccount; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.CashoutRecordService; +import com.jeequan.jeepay.service.impl.InfoAccountService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 提现结算记录表 + * + * @author xiaoyu + * @date 2022/3/21 10:00 + */ +@RestController +@RequestMapping("/api/cashout") +public class CashoutRecordController extends CommonCtrl { + + @Autowired private CashoutRecordService cashoutRecordService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private SysConfigService sysConfigService; + @Autowired private InfoAccountService infoAccountService; + + /** + * @author: xiaoyu + * @date: 2022/3/21 10:01 + * @describe: 提现记录 + */ + @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_LIST')") + @GetMapping + public ApiRes list() { + + CashoutRecord record = getObject(CashoutRecord.class); + JSONObject paramJSON = getReqParamJSON(); + record.setInfoId(getCurrentAgentNo()); + record.setInfoType(CS.SYS_ROLE_TYPE.AGENT); + LambdaQueryWrapper wrapper = CashoutRecord.gw(); + IPage pages = cashoutRecordService.listByPage(getIPage(), record, paramJSON, wrapper); + pages.getRecords().stream().forEach(i -> { + i.setSettAccountName(DesensitizedUtil.chineseName(i.getSettAccountName())); + i.setSettAccountTelphone(DesensitizedUtil.mobilePhone(i.getSettAccountTelphone())); + i.setSettAccountNo(DesensitizedUtil.bankCard(i.getSettAccountNo())); + + // 平台手续费不对服务商显示 + i.setTransferPlatformCostAmount(null); i.setTransferPlatformMchfeeAmount(null); + i.setTransferMchAppId(null); + i.setTransferIfCode(null); + i.setTransferOrderId(null); + }); + + return ApiRes.page(pages); + } + + /** + * @author: xiaoyu + * @date: 2022/3/21 10:21 + * @describe: 提现结算记录详情 + */ + @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_DETAIL')") + @GetMapping("/{rid}") + public ApiRes detail(@PathVariable("rid") String rid) { + Byte originData = getValByteDefault("originData", CS.YES); + + CashoutRecord record = cashoutRecordService.getById(rid); + if (CS.NO == originData) { + // 数据脱敏 + record.setSettAccountName(DesensitizedUtil.chineseName(record.getSettAccountName())); + record.setSettAccountTelphone(DesensitizedUtil.mobilePhone(record.getSettAccountTelphone())); + record.setSettAccountNo(DesensitizedUtil.bankCard(record.getSettAccountNo())); + } + + if (record == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + if (!record.getInfoId().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 钱包余额 + InfoAccount infoAccount = infoAccountService.queryById(getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT); + record.addExt("realBalanceAmount", infoAccount == null ? 0L : infoAccount.getBalanceAmount()); + record.addExt("unAmount", infoAccount == null ? 0L : infoAccount.getUnAmount()); + record.addExt("auditProfitAmount", infoAccount == null ? 0L : infoAccount.getAuditProfitAmount()); + // 页面上的钱包余额 + Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount(); + record.addExt("availableBalanceAmount", availableBalanceAmount); + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + // 冻结金额 及 冻结原因 + Long freezeAmount = agentInfo == null ? 0L : agentInfo.getFreezeAmount(); + record.addExt("freezeAmount", freezeAmount); + record.addExt("freezeDesc", agentInfo == null ? "" : agentInfo.getFreezeDesc()); + // 可提现金额(页面上的钱包余额-冻结金额) + record.addExt("allowTakeAmount", Math.max(availableBalanceAmount - freezeAmount, 0L)); + + // 平台手续费不对服务商显示 + record.setTransferPlatformCostAmount(null); record.setTransferPlatformMchfeeAmount(null); + record.setTransferMchAppId(null); + record.setTransferIfCode(null); + record.setTransferOrderId(null); + + return ApiRes.ok(record); + } + + /** + * @author: xiaoyu + * @date: 2022/3/21 10:21 + * @describe: 发起提现 + */ + @MethodLog( remark = "佣金提现") + @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_SETT')") + @PostMapping("/sett") + public ApiRes sett() { + + String sipw = Base64.decodeStr(getValStringRequired("sipw")); + + // 查询当前服务商结算信息 + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + if(StringUtils.isEmpty(agentInfo.getSipw())){ + throw new BizException("当前未设置支付密码,请进入[账号中心-系统配置-安全管理]设置支付密码"); + } + + if(!new BCryptPasswordEncoder().matches(sipw, agentInfo.getSipw())){ + throw new BizException("支付密码验证失败!"); + } + + // 结算参数 + AgentInfo infoParams = getObject(AgentInfo.class); + if (infoParams == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + if (StringUtils.isEmpty(agentInfo.getSettAccountType()) || StringUtils.isEmpty(agentInfo.getSettAccountNo())) { + throw new BizException("请先联系平台配置结算账户信息"); + } + if (StringUtils.isEmpty(infoParams.getContactTel()) || StringUtils.isEmpty(infoParams.getContactName())) { + throw new BizException("结算用户名/联系人手机号不可为空"); + } + + // 提现金额 元转分 + Long applyAmount = Long.valueOf(AmountUtil.convertDollar2Cent(getValStringRequired("amount"))); + + // 提现金额小于最大可提现金额才允许发起提现 + InfoAccount infoAccount = infoAccountService.queryById(agentInfo.getAgentNo(), CS.SYS_ROLE_TYPE.AGENT); + // 页面上的钱包余额 + Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount(); + // 可提现金额(页面上的钱包余额-冻结金额)单位:分 + if (applyAmount > Math.max(availableBalanceAmount - agentInfo.getFreezeAmount(), 0L)) { + throw new BizException("提现金额超限,请刷新页面后重试"); + } + + CashoutRecord record = getObject(CashoutRecord.class); + record.setApplyAmount(applyAmount); + + record.setState(CashoutRecord.CASHOUT_STATE_AUDIT_ING); // 待审核 + record.setInfoId(getCurrentAgentNo()); + record.setInfoType(CS.SYS_ROLE_TYPE.AGENT); + record.setInfoName(agentInfo.getAgentShortName()); + record.setSettType(CashoutRecord.SETT_TYPE_COMM); + + CashoutFee cashoutFee = null; + // 使用默认 + if(agentInfo.getCashoutFeeRuleType() == 1){ + cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class); + }else{ + cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class); + } + + if(cashoutFee.getApplyLimit() != null && record.getApplyAmount() < cashoutFee.getApplyLimit() ){ + throw new BizException("提现额度不可小于" + AmountUtil.convertCent2Dollar(cashoutFee.getApplyLimit()) + "元"); + } + + MutablePair feePair = cashoutFee.calFeeAndSnapshot(record.getApplyAmount()); + + record.setSettFeeRule(feePair.left); + record.setSettFeeAmount(feePair.right); + record.setSettAmount(record.getApplyAmount() - record.getSettFeeAmount()); + + if(record.getApplyAmount() <= 0 || record.getSettFeeAmount() < 0 || record.getSettAmount() <= 0){ + throw new BizException(String.format("提现金额计算错误! 申请: %s元, 手续费%s元, 到账:%s元", + AmountUtil.convertCent2Dollar(record.getApplyAmount()), + AmountUtil.convertCent2Dollar(record.getSettFeeAmount()), + AmountUtil.convertCent2Dollar(record.getSettAmount()) + )); + } + + // 结算账户信息 + record.setSettAccountType(agentInfo.getSettAccountType()); + + // 结算人姓名: 优先取值运营平台设置的费率, 如果为空,那么取 服务商申请时填入的。 + record.setSettAccountName(StringUtils.defaultIfEmpty(infoParams.getSettAccountName(), record.getContactName())); + record.setContactName(infoParams.getContactName()); + record.setSettAccountBank(agentInfo.getSettAccountBank()); + record.setSettAccountSubBank(agentInfo.getSettAccountSubBank()); + record.setSettAccountNo(agentInfo.getSettAccountNo()); + record.setSettAccountTelphone(infoParams.getContactTel()); + + // 发起提现 + cashoutRecordService.settAmount(record); + + return ApiRes.ok(); + } + + /** + * @author: xiaoyu + * @date: 2022/3/29 16:54 + * @describe: 获取当前服务商费率 + */ + @PreAuthorize("hasAuthority('ENT_CASHOUT_PAYWAY_FEE')") + @GetMapping("/paywayFee") + public ApiRes getPaywayFee() { + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + CashoutFee cashoutFee = null; + // 使用默认 + if(agentInfo.getCashoutFeeRuleType() == 1){ + cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class); + }else{ + cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class); + } + + return ApiRes.ok(cashoutFee); + } + + /** 统计 **/ + @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_COUNT')") + @GetMapping(value="/count") + public ApiRes count() { + + CashoutRecord record = getObject(CashoutRecord.class); + record.setInfoId(getCurrentAgentNo()); + Map result = cashoutRecordService.countByCashout(record); + + return ApiRes.ok(result); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/InfoAccountHistoryController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/InfoAccountHistoryController.java new file mode 100644 index 0000000..ad69afe --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/account/InfoAccountHistoryController.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.agent.ctrl.account; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.InfoAccountHistory; +import com.jeequan.jeepay.service.impl.InfoAccountHistoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 钱包流水 + * + * @author xiaoyu + * @date 2022/3/23 14:20 + */ +@RestController +@RequestMapping("/api/accountHistory") +public class InfoAccountHistoryController extends CommonCtrl { + + @Autowired private InfoAccountHistoryService infoAccountHistoryService; + + /** + * @author: xiaoyu + * @date: 2022/3/23 14:34 + * @describe: 钱包流水 + */ + @PreAuthorize("hasAuthority('ENT_ACCOUNT_HISTORY_LIST')") + @GetMapping + public ApiRes list() { + + InfoAccountHistory history = getObject(InfoAccountHistory.class); + history.setInfoId(getCurrentAgentNo()); + history.setInfoType(CS.SYS_ROLE_TYPE.AGENT); + IPage pages = infoAccountHistoryService.listByPage(getIPage(), history); + + return ApiRes.page(pages); + } + + /** + * @author: xiaoyu + * @date: 2022/3/23 14:34 + * @describe: 钱包流水详情 + */ + @PreAuthorize("hasAuthority('ENT_ACCOUNT_HISTORY_DETAIL')") + @GetMapping("/{hid}") + public ApiRes detail(@PathVariable("hid") String hid) { + InfoAccountHistory history = infoAccountHistoryService.getById(hid); + if (history == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + if (!history.getInfoId().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + return ApiRes.ok(history); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/agentconfig/AgentConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/agentconfig/AgentConfigController.java new file mode 100644 index 0000000..90bb8aa --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/agentconfig/AgentConfigController.java @@ -0,0 +1,130 @@ +package com.jeequan.jeepay.agent.ctrl.agentconfig; + +import cn.hutool.core.codec.Base64; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.AgentConfig; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.ThirdAuthDataEntity; +import com.jeequan.jeepay.service.impl.AgentConfigService; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.ThirdAuthDataService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.*; + +/*** +* 服务商配置 +* +* @author terrfly +* +* @date 2022/5/24 11:12 +*/ +@RestController +@RequestMapping("/api/agentConfig") +public class AgentConfigController extends CommonCtrl { + + @Autowired private AgentInfoService agentInfoService; + @Autowired private AgentConfigService agentConfigService; + + @Autowired + private ThirdAuthDataService thirdAuthDataService; + + + @MethodLog(remark = "更改支付密码") + @PutMapping("/agentSipw") + public ApiRes updateSipw() { + + String confirmPwd = Base64.decodeStr(getValStringRequired("confirmPwd")); + + // 验证原密码 + AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + if(StringUtils.isNotEmpty(dbAgentInfo.getSipw())){ + //当前旧密码 + String originalPwd = Base64.decodeStr(getValStringRequired("originalPwd")); + if(!new BCryptPasswordEncoder().matches(originalPwd, dbAgentInfo.getSipw())){ + throw new BizException("原支付验证失败!"); + } + } + + AgentInfo agentInfo = new AgentInfo(); + agentInfo.setAgentNo(getCurrentAgentNo()); + agentInfo.setSipw(new BCryptPasswordEncoder().encode(confirmPwd)); + agentInfoService.updateById(agentInfo); + return ApiRes.ok(); + } + + + /** 是否设置了支付密码 **/ + @GetMapping("/hasSipwValidate") + public ApiRes hasSipwValidate() { + + AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + + return ApiRes.ok(StringUtils.isNotEmpty(dbAgentInfo.getSipw())); + } + + /** 验证支付密码是否正确 **/ + @PostMapping("/agentSipwValidate") + public ApiRes agentSipwValidate() { + + //当前旧密码 + String originalPwd = Base64.decodeStr(getValStringRequired("originalPwd")); + + // 验证原密码 + AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + + + return ApiRes.ok(StringUtils.isEmpty(dbAgentInfo.getSipw()) || new BCryptPasswordEncoder().matches(originalPwd, dbAgentInfo.getSipw())); + + } + + /** + * 根据configKey查询服务商配置 + */ + @GetMapping("/{configKey}") + public ApiRes get(@PathVariable("configKey") String configKey) { + AgentConfig config = agentConfigService.getByAgentNoAndConfigKey(getCurrentAgentNo(), configKey); + return ApiRes.ok(config); + } + + + @PostMapping("/authData") + public ApiRes addAuthData() { + ThirdAuthDataEntity entity = getObject(ThirdAuthDataEntity.class); + Assert.notNull(entity.getType(), "授权渠道[type]不能为空"); + Assert.notNull(entity.getSubType(), "授权类型[subType]不能为空"); + Assert.notNull(entity.getAuthFileName(), "文件名称[authFileName]不能为空"); + Assert.notNull(entity.getValue(), "文件内容[value]不能为空"); + + ThirdAuthDataEntity one = thirdAuthDataService.lambdaQuery() + .eq(ThirdAuthDataEntity::getAuthFileName, entity.getAuthFileName()) + .one(); + + if (one != null) { + throw new BizException("数据已存在"); + } + + thirdAuthDataService.save(entity); + + return ApiRes.ok(); + } + + @PostMapping("/config") + public ApiRes setConfig() { + AgentConfig reqParam = getObject(AgentConfig.class); + Assert.notNull(reqParam, "缺少参数"); + Assert.notNull(reqParam.getGroupKey(), "配置分组名称代码[groupKey]不能为空"); + Assert.notNull(reqParam.getConfigKey(), "配置名称代码[configKey]不能为空"); + Assert.notNull(reqParam.getAgentNo(), "服务商编号[agentNo]不能为空"); + Assert.notNull(reqParam.getConfigVal(), "配置项[configVal]未赋值"); + + agentConfigService.saveOrUpdateConfig(reqParam); + + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/AuthController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/AuthController.java new file mode 100644 index 0000000..3b56cc2 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/AuthController.java @@ -0,0 +1,153 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import cn.hutool.captcha.CaptchaUtil; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.bizcommons.manage.auth.AuthByQrcodeManage; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.JsonKit; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * 登录鉴权 + * + * @author terrfly + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("/api/anon/auth") +public class AuthController extends CommonCtrl { + + @Autowired private AuthService authService; + @Autowired private SmsManager smsManager; + + /** 用户信息认证 获取iToken **/ + @RequestMapping(value = "/validate", method = RequestMethod.POST) + @MethodLog(remark = "登录认证") + public ApiRes validate() throws BizException { + + String loginPageType = Base64.decodeStr(getValStringRequired("lt")); //登录页面(终端)类型, 已做base64处理 + + // 是否app登录 + boolean isApp = loginPageType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginPageType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE); + + String account = Base64.decodeStr(getValStringRequired("ia")); //用户名 i account, 已做base64处理 + String ipassport = Base64.decodeStr(getValStringRequired("ip")); //密码 i passport, 已做base64处理 + + String vercode = isApp ? "" : Base64.decodeStr(getValStringRequired("vc")); // 验证码 vercode, 已做base64处理 + String vercodeToken = isApp ? "" : Base64.decodeStr(getValStringRequired("vt")); //验证码token, vercode token , 已做base64处理 + + String mfaCode = StringUtils.isEmpty(getValString("mc")) ? null : Base64.decodeStr(getValString("mc")); // MFACode, 已做base64处理 + + // 验证码校验: WEB登录 & 第一次认证(MFACode为空的情况) + if(!isApp && StringUtils.isEmpty(mfaCode)){ + String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vercodeToken)); + if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vercode)){ + throw new BizException("验证码有误!"); + } + } + + // 返回前端 accessToken + return authService.authByAuthentication(account, ipassport, loginPageType, vercodeToken, mfaCode); + } + + /** 用户信息认证[手机验证码登录] 获取iToken **/ + @RequestMapping(value = "/phoneCode", method = RequestMethod.POST) + @MethodLog(remark = "手机验证码登录") + public ApiRes phoneCode() throws BizException { + + String loginPageType = Base64.decodeStr(getValStringRequired("lt")); //登录页面(终端)类型, 已做base64处理 + String phone = Base64.decodeStr(getValStringRequired("phone")); // 手机号, 已做base64处理 + String code = Base64.decodeStr(getValStringRequired("code")); // 验证码 code, 已做base64处理 + + // 校验验证码 && 如果有异常 抛异常 + smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_AUTH); + + // 返回前端 accessToken + return authService.authByPhoneCode(phone, loginPageType); + } + + /** 图片验证码 **/ + @RequestMapping(value = "/vercode", method = RequestMethod.GET) + public ApiRes vercode() throws BizException { + + //定义图形验证码的长和宽 // 4位验证码 + LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(137, 40, 4, 80); + lineCaptcha.createCode(); //生成code + + //redis + String vercodeToken = UUID.fastUUID().toString(); + RedisUtil.setString(CS.getCacheKeyImgCode(vercodeToken), lineCaptcha.getCode(), CS.VERCODE_CACHE_TIME ); //图片验证码缓存时间: 1分钟 + + JSONObject result = new JSONObject(); + result.put("imageBase64Data", lineCaptcha.getImageBase64Data()); + result.put("vercodeToken", vercodeToken); + result.put("expireTime", CS.VERCODE_CACHE_TIME); + + return ApiRes.ok(result); + } + + + /** 轮询 登录二维码状态 **/ + @GetMapping("/qrcodeStatus") + public ApiRes qrcodeStatus() { + + String qrcodeNo = getValString("qrcodeNo"); + + // 未传入qrcodeNo,直接返回一个,并存入redis,key:JEEPAY_LOGIN_QR_qrcodeNo + if (StringUtils.isBlank(qrcodeNo)) { + qrcodeNo = CS.getCacheKeyLoginQrcode(IdUtil.simpleUUID()); + AuthByQrcodeManage.setQrcodeStatusWaiting(qrcodeNo); + return ApiRes.ok(JsonKit.newJson("qrcodeNo", qrcodeNo)); + } + + // 根据传入的qrcodeNo,判断二维码被扫状态 + String qrCodeStatus = RedisUtil.getString(qrcodeNo); + + // redis未查询到qrcodeNo信息 + if (StringUtils.isBlank(qrCodeStatus)) { + return ApiRes.ok(JsonKit.newJson("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_EXPRIED)); + } + + JSONObject resJSON = new JSONObject(); + + if (qrCodeStatus.startsWith(AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED + "_")){ + + String tokenStr = qrCodeStatus.replaceFirst(AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED + "_", ""); + resJSON = JSONObject.parseObject(tokenStr); + resJSON.put("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED); + + // 清空二维码缓存 + AuthByQrcodeManage.delQrcodeStatus(qrcodeNo); + + }else if (qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_CANCELED)){ + + resJSON.put("qrcodeStatus", AuthByQrcodeManage.QRCODE_STATUS_CANCELED); + + // 清空二维码缓存 + AuthByQrcodeManage.delQrcodeStatus(qrcodeNo); + + }else { + resJSON.put("qrcodeStatus", qrCodeStatus); + } + + return ApiRes.ok(resJSON); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/ClientVersionController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/ClientVersionController.java new file mode 100644 index 0000000..0f86668 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/ClientVersionController.java @@ -0,0 +1,110 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.SysClientVersion; +import com.jeequan.jeepay.service.impl.SysClientVersionService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 版本管理 + * + * @author xiaoyu + * @date 2021/12/31 11:11 + */ +@Slf4j +@RestController +@RequestMapping("/api/anon/clientVersion") +public class ClientVersionController extends CommonCtrl { + + @Autowired private SysClientVersionService sysClientVersionService; + + /** + * @author: xiaoyu + * @date: 2021/12/31 11:28 + * @describe: 版本信息 + */ + @RequestMapping(value = "/versionInfo", method = RequestMethod.GET) + public ApiRes versionInfo() { + // 版本号 + String versionNumber = getValStringRequired("versionNumber"); + SysClientVersion dbClientVersion = sysClientVersionService.getOne( + SysClientVersion.gw() + .eq(SysClientVersion::getClientType, SysClientVersion.CLIENT_TYPE_AGENT) + .eq(SysClientVersion::getVersionSerialNumber, versionNumber) + ); + + //未查询到当前版本信息, 查询最新版本作为 需[强制更新] 的版本 + if(dbClientVersion == null){ + List newVersionList = sysClientVersionService.page( + new Page<>(1, 1), + new QueryWrapper().lambda().eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT).orderByDesc(SysClientVersion:: getVersionId) + ).getRecords(); + if(newVersionList != null && !newVersionList.isEmpty()){ + SysClientVersion newVersion = newVersionList.get(0); + newVersion.setForceUpdate(CS.YES); + return ApiRes.ok(newVersion); + }else{ + //未查询到 任何版本信息 + return ApiRes.ok(new JSONObject()); + } + } + + // 查询到当前版本信息, 需查询当前版本之后的最新版本信息 + List newVersionList = sysClientVersionService.page( + new Page<>(1, 1), + new QueryWrapper().lambda() + .eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT) + .gt(SysClientVersion:: getVersionId, dbClientVersion.getVersionId()) + .orderByDesc(SysClientVersion:: getVersionId) + ).getRecords(); + + if(newVersionList == null || newVersionList.isEmpty()){ + //未查询到 任何版本信息 + return ApiRes.ok(new JSONObject()); + } + //最新版本信息 + SysClientVersion newVersion = newVersionList.get(0); + + //如果当前版本前,包含强制更新, 则更改当前版本为强制更新版本 + long count = sysClientVersionService.count( + new QueryWrapper().lambda() + .eq(SysClientVersion:: getClientType, SysClientVersion.CLIENT_TYPE_AGENT) + .eq(SysClientVersion:: getForceUpdate, CS.YES) + .gt(SysClientVersion:: getVersionId, dbClientVersion.getVersionId()) + ); + if(count > 0){ + newVersion.setForceUpdate(CS.YES); + } + return ApiRes.ok(newVersion); + } + + /** + * @author: yr + * @date: 2023/02/10 16:20 + * @describe: 服务商App获取最新版下载url + */ + @RequestMapping(value = "/downloadUrl", method = RequestMethod.GET) + public ApiRes downloadUrl() { + LambdaQueryWrapper wrapper = SysClientVersion.gw(); + wrapper.eq(SysClientVersion::getClientType, SysClientVersion.CLIENT_TYPE_AGENT); + if (sysClientVersionService.count(wrapper) == 0){ + return ApiRes.ok(); + } + wrapper.orderByDesc(SysClientVersion::getVersionId); + wrapper.last("limit 1"); + return ApiRes.ok(sysClientVersionService.getOne(wrapper).getDownloadUrl()); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RegisterController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RegisterController.java new file mode 100644 index 0000000..54693c0 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RegisterController.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import cn.hutool.core.codec.Base64; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 服务商注册 + * + * @author xiaoyu + * @date 2021/12/30 14:59 + */ +@RestController +@RequestMapping("/api/anon/register") +public class RegisterController extends CommonCtrl { + + @Autowired private SmsManager smsManager; + + /** 服务商注册接口 **/ + @PostMapping(value = "/agentRegister") + @MethodLog(remark = "服务商注册") + public ApiRes retrieve() throws BizException { + + // 服务商名称, 已做base64处理 + String agentName = getValStringRequired("agentName"); + // 手机号, 已做base64处理 + String phone = Base64.decodeStr(getValStringRequired("phone")); + // 验证码, 已做base64处理 + String code = Base64.decodeStr(getValStringRequired("code")); + // 确认密码 confirmPassword, 已做base64处理 + String confirmPwd = Base64.decodeStr(getValStringRequired("confirmPwd")); + // 邀请码 + String inviteCode = getValString("inviteCode"); + + // 校验验证码 && 如果有异常 抛异常 + smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_REGISTER); + + // 注册服务商 + agentInfoService.mchRegister(phone, confirmPwd, agentName, inviteCode); + + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RetrieveController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RetrieveController.java new file mode 100644 index 0000000..15a8b9f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/RetrieveController.java @@ -0,0 +1,82 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import cn.hutool.core.codec.Base64; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBsecurityConfig; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.service.impl.SysUserAuthService; +import com.jeequan.jeepay.service.impl.SysUserService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/* +* 登录密码接口 +* +* @author xiaoyu +* @date 2021/6/8 17:09 +*/ +@RestController +@RequestMapping("/api/anon/cipher") +public class RetrieveController extends CommonCtrl { + + @Autowired private SysUserService sysUserService; + @Autowired private SysUserAuthService sysUserAuthService; + @Autowired private SysConfigService sysConfigService; + @Autowired private SmsManager smsManager; + + + /** 密码找回接口 **/ + @RequestMapping(value = "/retrieve", method = RequestMethod.POST) + @MethodLog(remark = "密码找回") + public ApiRes retrieve() throws BizException { + + // 手机号, 已做base64处理 + String phone = Base64.decodeStr(getValStringRequired("phone")); + // 验证码, 已做base64处理 + String code = Base64.decodeStr(getValStringRequired("code")); + // 新密码 password, 已做base64处理 + String newPwd = Base64.decodeStr(getValString("newPwd")); + + // 验证手机号 + smsManager.checkSmsVercodeThrowBizEx(phone, code, CS.SMS_TYPE_API_ENUM.TYPE_RETRIEVE); + + SysUserEntity dbUser = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getTelphone, phone).eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT)); + if (dbUser == null) { + throw new BizException("用户不存在"); + } + if (StringUtils.isNotEmpty(newPwd)) { + // 更新用户登录密码 + sysUserAuthService.resetAuthInfo(dbUser.getSysUserId(), null, null, true, newPwd, CS.SYS_ROLE_TYPE.AGENT); + // TODO mq更新用户密码 + } + + return ApiRes.ok(); + } + + /** 获取密码校验规则正则 **/ + @RequestMapping(value = "/pwdRulesRegexp", method = RequestMethod.GET) + public ApiRes getPwdRulesRegexp() throws BizException { + + + DBsecurityConfig.PasswordRegexp passwordRegexp = sysConfigService.getDBSecurityConfig().getPasswordRegexp(); + JSONObject resultJson = null; + if (passwordRegexp != null) { + resultJson = (JSONObject) JSONObject.toJSON(passwordRegexp); + // 查询是否需要审核 + String subIsAudit = sysConfigService.getDBDefaultConfig().getAgentNewSubIsAudit(); + resultJson.put("subIsAudit", subIsAudit); + } + return ApiRes.ok(resultJson); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SiteInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SiteInfoController.java new file mode 100644 index 0000000..75f9606 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SiteInfoController.java @@ -0,0 +1,80 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBOEMConfig; +import com.jeequan.jeepay.core.service.ISysConfigService; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.db.entity.AgentConfig; +import com.jeequan.jeepay.service.impl.AgentConfigService; +import com.jeequan.jeepay.service.impl.SysAdvertConfigService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 网站信息ctrl + * + * @author terrfly + * @date 2022/2/14 20:56 + */ +@RestController +@RequestMapping("/api/anon/siteInfos") +public class SiteInfoController extends CommonCtrl { + + @Autowired + private ISysConfigService sysConfigService; + @Autowired + private SysAdvertConfigService advertConfigService; + @Autowired + private AgentConfigService agentConfigService; + + @GetMapping(value = "") + public ApiRes getSiteInfos() throws BizException { + + JSONObject result = new JSONObject(); + result.put("sysConfig", JsonKit.newJson("httpMsgIsEncrypt", SysConfigService.HTTP_MSG_IS_ENCRYPT)); + DBOEMConfig dboemConfig = sysConfigService.getOemConfig(); + //获取域名 + String headerDomainName = getdomainName(); + if (headerDomainName != null && headerDomainName.contains("//")) { + int startIndex = headerDomainName.indexOf("//") + 2; // 获取第一个 "//" 后的位置 + int endIndex = headerDomainName.indexOf("/", startIndex); // 获取从 startIndex 开始的第一个 "/" + if (endIndex != -1) { + String domainName = headerDomainName.substring(startIndex, endIndex); + result.put("domainName", domainName); + AgentConfig agentConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigVal, domainName).last("limit 1")); + if (agentConfig == null) { + //该域名没配置,取总后台数据 + result.put("siteInfo", dboemConfig); + return ApiRes.ok(result); + } + //获取商户域名 + AgentConfig mchDomainName = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigKey, "mchSiteUrl").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo())); + if (mchDomainName != null) { + result.put("mchDomainName", mchDomainName.getConfigVal()); + } + //获取服务商域名 + AgentConfig agentDomainName = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig").eq(AgentConfig::getConfigKey, "agentSiteUrl").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo())); + if (mchDomainName != null) { + result.put("agentDomainName", agentDomainName.getConfigVal()); + } + AgentConfig oemConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getConfigKey, "oemConfig").eq(AgentConfig::getAgentNo, agentConfig.getAgentNo())); + if (oemConfig == null) { + //贴牌数据为空,取总后台数据 + result.put("siteInfo", dboemConfig); + return ApiRes.ok(result); + } + result.put("siteInfo", JSONObject.parseObject(oemConfig.getConfigVal())); + + } + } + return ApiRes.ok(result); + + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SmsCodeController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SmsCodeController.java new file mode 100644 index 0000000..fd80dd5 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/SmsCodeController.java @@ -0,0 +1,75 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.service.impl.SysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/* + * 短信验证 + * + * @author xiaoyu + * @date 2021/6/8 17:09 + */ +@RestController +@RequestMapping("/api/anon/sms") +public class SmsCodeController extends CommonCtrl { + + @Autowired + private SysUserService sysUserService; + @Autowired + private SmsManager smsManager; + + /** + * 发送短信验证码 + **/ + @RequestMapping(value = "/code", method = RequestMethod.POST) + public ApiRes code() throws BizException { + // 验证参数 手机号, 已做base64处理 + String phone = getValStringRequired("phone"); + String smsType = getValStringRequired("smsType"); + + String vercodeToken = getValStringRequired("vercodeToken"); + String vercode = getValStringRequired("vercode"); + + String redisVercode = RedisUtil.getString(CS.getCacheKeyImgCode(vercodeToken)); + if (!vercode.equalsIgnoreCase(redisVercode)) { + throw new BizException("验证码错误"); + } + + // 校验用户 + checkUser(phone, smsType); + + // 发送短信 + smsManager.sendSmsVercode(phone, smsType); + + return ApiRes.ok(); + } + + /** + * @author: xiaoyu + * @date: 2022/1/14 9:01 + * @describe: 校验用户是否存在 + */ + private void checkUser(String phone, String smsType) { + SysUserEntity dbUser = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getTelphone, phone).eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT)); + if (CS.SMS_TYPE_API_ENUM.TYPE_REGISTER.equals(smsType)) { + if (dbUser != null) { + throw new BizException("当前用户已存在"); + } + } else { + if (dbUser == null) { + throw new BizException("用户不存在"); + } + } + + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/TreatyController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/TreatyController.java new file mode 100644 index 0000000..bd0f18b --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/anon/TreatyController.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.agent.ctrl.anon; + +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.AgentConfig; +import com.jeequan.jeepay.service.impl.AgentConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 服务政策 隐私协议ctrl + * + * @author xiaoyu + * @date 2022/2/16 14:51 + */ +@RestController +@RequestMapping("/api/anon/treaty") +public class TreatyController extends CommonCtrl { + + @Autowired private AgentConfigService agentConfigService; + + + @GetMapping(value = "") + public ApiRes getTreaty() throws BizException { + Map result = new HashMap<>(); + //获取域名 + String headerDomainName = getdomainName(); + if (headerDomainName != null && headerDomainName.contains("//")) { + int startIndex = headerDomainName.indexOf("//") + 2; // 获取第一个 "//" 后的位置 + int endIndex = headerDomainName.indexOf("/", startIndex); // 获取从 startIndex 开始的第一个 "/" + if (endIndex != -1) { + String domainName = headerDomainName.substring(startIndex, endIndex); + AgentConfig agentConfig = agentConfigService.getOne(AgentConfig.gw().eq(AgentConfig::getGroupKey, "agentSiteConfig") + .eq(AgentConfig::getConfigVal,domainName) + .last("limit 1")); + if (agentConfig == null){ + //该域名没配置,取总后台数据 + return ApiRes.ok(sysConfigService.getTreatyConfig()); + } + List treatyConfigList = agentConfigService.list(AgentConfig.gw().eq(AgentConfig::getGroupKey, "treatyConfig") + .eq(AgentConfig::getAgentNo,agentConfig.getAgentNo())); + if(treatyConfigList.isEmpty()){ + //贴牌数据为空,取总后台数据 + return ApiRes.ok(sysConfigService.getTreatyConfig()); + }else { + for (AgentConfig config : treatyConfigList) { + result.put(config.getConfigKey(), config.getConfigVal()); + } + return ApiRes.ok(result); + } + } + } + return ApiRes.ok(sysConfigService.getTreatyConfig()); + + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/DefaultConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/DefaultConfigController.java new file mode 100644 index 0000000..cb7c862 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/DefaultConfigController.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.agent.ctrl.applyment; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBDefaultConfig; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 系统默认配置 + * + * @author xiaoyu + * + * @date 2023/4/11 9:38 + */ +@RestController +@RequestMapping("/api/defaultConfig") +public class DefaultConfigController extends CommonCtrl { + + /** 平台默认配置查询 **/ + @GetMapping("") + public ApiRes getDefaultConfig() { + JSONObject result = new JSONObject(); + // 进件图片大小默认配置 + DBDefaultConfig defaultConfig = sysConfigService.getDBDefaultConfig(); + result.put("applymentImgUploadSize", defaultConfig.getApplymentImgUploadSize()); + + return ApiRes.ok(result); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/KqpayMchApplymentController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/KqpayMchApplymentController.java new file mode 100644 index 0000000..99bef77 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/KqpayMchApplymentController.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.agent.ctrl.applyment; + +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayMchApplymentService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +@RestController +@RequestMapping("/api/mchApplyments") +public class KqpayMchApplymentController extends CommonCtrl { + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private KqpayMchApplymentService kqpayMchApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @PostMapping("/kqSignApply/{recordId}") + public ApiRes signApply(@PathVariable("recordId") String recordId) { + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = kqpayMchApplymentService.signApply(mchInfoConverter.toModel(dbRecord)); + + MchApplyment applymentResult = new MchApplyment(); + BeanUtils.copyProperties(mchApplyment, applymentResult); + + // 当状态发生了变化时 + if (!dbRecord.getState().equals(applymentResult.getState())) { + + // 更新数据 + applymentResult.setApplyId(recordId); + applymentResult.setLastApplyAt(new Date()); + mchApplymentService.updateById(applymentResult); + } + return ApiRes.ok(applymentResult); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/LklspayMchApplymentController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/LklspayMchApplymentController.java new file mode 100644 index 0000000..8fe6a00 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/LklspayMchApplymentController.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.agent.ctrl.applyment; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/api/mchApplyments") +public class LklspayMchApplymentController { + + /** 拉卡拉获取银行信息列表 **/ + @GetMapping("/getLklBankList/{areaCode}/{branchName}") + public ApiRes getLklBankList(@PathVariable("areaCode") String areaCode, @PathVariable("branchName") String branchName) { + HttpResponse httpResponse = null; + try { + String result = null; + if (StringUtils.isNotEmpty(areaCode)) { + httpResponse = HttpRequest.get("https://tkapi.lakala.com/registration/bank?areaCode=" + areaCode + "&bankName=" + branchName).execute(); + result = httpResponse.body(); + } + return ApiRes.ok(result); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } finally { + if (httpResponse != null) { + httpResponse.close(); + } + } + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/MchApplymentController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/MchApplymentController.java new file mode 100644 index 0000000..6e19d6f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/MchApplymentController.java @@ -0,0 +1,1831 @@ +package com.jeequan.jeepay.agent.ctrl.applyment; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.components.mq.model.MchAuditMQ; +import com.jeequan.jeepay.components.mq.model.MchAuditThirdNotifyMQ; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.*; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.IsvChannelConfig; +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.hmpay.HmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.utmpay.UtmpayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 进件管理 + * + * @author terrfly + * @date 2021/12/27 15:26 + */ +@Slf4j +@RestController +@RequestMapping("/api/mchApplyments") +public class MchApplymentController extends CommonCtrl { + + @Autowired + private IsvInfoService isvInfoService; + @Autowired + private MchApplymentService mchApplymentService; + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private MchAppService mchAppService; + @Autowired + private IMQSender mqSender; + @Autowired + private RateConfigService rateConfigService; + @Autowired + private AgentConfigService agentConfigService; + @Autowired + private ConfigContextQueryService configContextQueryService; + @Autowired + private MchAppApplymentService mchAppApplymentService; + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Autowired + private MchPayInterfaceConfigService mchPayInterfaceConfigService; + @Autowired + private TransactionTemplate transactionTemplate; + + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_LIST')") + @GetMapping + public ApiRes list() { + MchApplyment searchRecord = getObject(MchApplyment.class); + Page page = getIPage(false); + //联系电话解密 + if (StringUtils.isNotEmpty(searchRecord.getContactName())) { + searchRecord.setContactPhone(SysConfigService.DB_ENCRYPT_SM4.encryptBase64(searchRecord.getContactName())); + } + // 扩展员仅查询自己的数据 + if (getCurrentUser().isEpUser()) { + searchRecord.setEpUserId(getCurrentUser().getSysUser().getSysUserId()); + } + // 可查看自己和全部下级服务商 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + if (CollectionUtil.isNotEmpty(subAgentNoList)) { + searchRecord.setSubAgentNoList(subAgentNoList); + } + //searchRecord.setAgentNo(getCurrentAgentNo()); + Page result = mchApplymentService.selectMchApplyment(page, searchRecord); + Optional.ofNullable(result).map(Page::getRecords) + .ifPresent(itemList -> { + for (MchApplyment item : itemList) { + // 运营商端返回全部备注 + item.setRemark(item.getAgtRemark()); + item.setMgrRemark(null); + item.setMchRemark(null); + } + }); + + return ApiRes.page(result); + } + + /** + * 保存备注信息 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_LIST')") + @PostMapping("/remark") + public ApiRes remark() { + String remark = getValString("remark"); + String applyId = getValString("applyId"); + + Assert.notNull(applyId, "[applyId]不能为空"); + + MchApplyment existData = mchApplymentService.getById(applyId); + Assert.notNull(existData, "进件信息不存在"); + + String existRemark = existData.getRemark(); + JSONObject remarkJSON = null; + try { + remarkJSON = JSON.parseObject(existRemark); + } finally { + if (remarkJSON == null) { + remarkJSON = new JSONObject(); + } + remarkJSON.put("agt", remark); + } + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + uWrapper.eq(MchApplyment::getApplyId, applyId); + uWrapper.set(MchApplyment::getRemark, remarkJSON.toJSONString()); + mchApplymentService.update(uWrapper); + + return ApiRes.ok(); + } + + /** + * 标记风控 / 解除标记风控 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_LIST')") + @PostMapping("/state") + public ApiRes riskMark() { + byte state = getValByte("state"); + String remark = getValString("remark"); + String applyId = getValString("applyId"); + + Assert.notNull(state, "状态不能为空"); + + + Assert.notNull(applyId, "[applyId]不能为空"); + + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + qWrapper.eq(MchApplyment::getApplyId, applyId); + MchApplyment existData = mchApplymentService.getOne(qWrapper); + + if (state != MchApplyment.STATE_WAIT_RISK + && state != MchApplyment.STATE_WAIT_FREEZE + && state != MchApplyment.STATE_WAIT_LOGOUT + && state != MchApplyment.STATE_SUCCESS) { + throw new BizException("状态参数[state]非法"); + } + + if (state == MchApplyment.STATE_SUCCESS) { + if (existData.getState() != MchApplyment.STATE_WAIT_RISK + && existData.getState() != MchApplyment.STATE_WAIT_FREEZE + && existData.getState() != MchApplyment.STATE_WAIT_LOGOUT) { + throw new BizException("当前商户状态不支持该操作"); + } + } + + if (state == MchApplyment.STATE_WAIT_RISK) { + if (existData.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前商户状态不支持该操作"); + } + } + + if (state == MchApplyment.STATE_WAIT_FREEZE) { + if (existData.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前商户状态不支持该操作"); + } + } + + if (state == MchApplyment.STATE_WAIT_LOGOUT) { + if (existData.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前商户状态不支持该操作"); + } + } + + String existRemark = existData.getRemark(); + JSONObject remarkJSON = null; + try { + remarkJSON = JSON.parseObject(existRemark); + } finally { + if (remarkJSON == null) { + remarkJSON = new JSONObject(); + } + remarkJSON.put("agt", remark); + } + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + uWrapper.eq(MchApplyment::getApplyId, applyId); + uWrapper.set(MchApplyment::getRemark, remarkJSON.toJSONString()); + uWrapper.set(MchApplyment::getState, state); + + mchApplymentService.update(uWrapper); + + return ApiRes.ok(); + } + + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_GET_INFO')") + @GetMapping("/channelState/{recordId}") + public ApiRes channelState(@PathVariable("recordId") String recordId) { + MchApplyment record = mchApplymentService.getById(recordId); + + if (record == null || !record.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("数据不存在"); + } + + // 只有 1 4 5 需要查询 + if (record.getRemainStep() != null && record.getRemainStep() > 0 && record.getState() == MchApplyment.STATE_AUDITING) { + throw new BizException("商户数据提交请求中"); + } + + if (record.getState() != MchApplyment.STATE_AUDITING + && record.getState() != MchApplyment.STATE_WAIT_VERIFY + && record.getState() != MchApplyment.STATE_WAIT_SIGN + && record.getState() != MchApplyment.STATE_FINISH_SIGN + && record.getState() != MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY) { + throw new BizException("当前状态无需查询"); + } + + IIsvmchApplymentService applymentService = IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(record.getIfCode())); + // 调起进件查询接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = applymentService.query(mchInfoConverter.toModel(record)); + MchApplyment applymentResult = new MchApplyment(); + mchInfoConverter.cp(applymentResultByRPC, applymentResult); + + // 当状态发生了变化时 + if (!record.getState().equals(applymentResult.getState())) { + + // 更新数据 + applymentResult.setApplyId(recordId); + applymentResult.setLastApplyAt(new Date()); + mchApplymentService.updateById(applymentResult); + + boolean beforeSuccess = record.getState() == MchApplyment.STATE_SUCCESS || record.getState() == MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY; + boolean resultSuccess = applymentResult.getState() == MchApplyment.STATE_SUCCESS || applymentResult.getState() == MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY; + boolean successFlag = resultSuccess && !beforeSuccess; + + if (successFlag) { + mchApplymentService.onApplymentSuccess(applymentResult.getApplyId()); + mqSender.send(MchAuditThirdNotifyMQ.build(recordId, MchAuditThirdNotifyMQ.TYPE_AUDIT)); + } + } + + return ApiRes.ok(applymentResult); + } + + + /** + * 查询合同最新信息 + **/ + @GetMapping("/channelSignInfo/{recordId}") + public ApiRes channelSignInfo(@PathVariable("recordId") String recordId) { + MchApplyment record = mchApplymentService.getById(recordId); + + if (record == null || !record.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("数据不存在"); + } + + // 放置签约额外参数(用于标识是否重签等) + record.addExt("extSignInfo", getValString("extSignInfo")); + // 调起接口 + IIsvmchApplymentService applymentService = IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(record.getIfCode())); + return ApiRes.ok(applymentService.signInfo(mchInfoConverter.toModel(record))); + } + + + /** + * 查询最新的微信开户意愿状态 + **/ + @GetMapping("/channelWxOpenInfo/{recordId}") + public ApiRes channelWxOpenInfo(@PathVariable("recordId") String recordId) { + MchApplyment record = mchApplymentService.getById(recordId); + + if (record == null || !record.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("数据不存在"); + } + + // 调起接口 + IIsvmchWxConfigService isvmchWxConfigService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(record.getIfCode()) + "IsvmchWxConfigService", IIsvmchWxConfigService.class); + return ApiRes.ok(isvmchWxConfigService.wxOpenSignInfo(mchInfoConverter.toModel(record))); + } + + /** + * 查询最新的支付宝开户意愿状态 + **/ + @GetMapping("/channelAlipayOpenInfo/{recordId}") + public ApiRes channelAlipayOpenInfo(@PathVariable("recordId") String recordId) { + MchApplyment mRecord = mchApplymentService.getById(recordId); + + if (mRecord == null) { + throw new BizException("数据不存在"); + } + + // 调起接口 + IIsvmchAlipayConfigService isvmchAlipayConfigService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(mRecord.getIfCode()) + "IsvmchAlipayConfigService", IIsvmchAlipayConfigService.class); + + return ApiRes.ok(isvmchAlipayConfigService.alipayOpenSignInfo(mchInfoConverter.toModel(mRecord))); + } + + + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_VIEW')") + @GetMapping("/{recordId}") + public ApiRes detail(@PathVariable("recordId") String recordId) { + Byte originData = getValByteDefault("originData", CS.NO); + MchApplyment mRecord; + if (CS.NO == originData) { + mRecord = mchApplymentService.getInfoById(recordId); + } else { + mRecord = mchApplymentService.getById(recordId); + } + if (mRecord == null || !mRecord.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.ok(); + } + //返回数据增加名称字段 + if (StringUtils.isNotEmpty(mRecord.getIsvNo())) { + IsvInfoEntity isvInfoEntity = isvInfoService.getById(mRecord.getIsvNo()); + if (isvInfoEntity != null){ + mRecord.setIsvName(isvInfoEntity.getIsvName()); + } + } + if (StringUtils.isNotEmpty(mRecord.getAgentNo())) { + AgentInfo agentInfo = agentInfoService.getById(mRecord.getAgentNo()); + if (agentInfo != null){ + mRecord.setAgentNoName(agentInfo.getAgentName()); + mRecord.setAgentPhone(agentInfo.getContactTel()); + } + } + + mRecord.setRemark(mRecord.getAgtRemark()); + mRecord.setMgrRemark(null); + mRecord.setMchRemark(null); + + return ApiRes.ok(mRecord); + } + + /** + * 获取合并的进件信息 + **/ + @GetMapping("/mergeApplyDetailInfos/{mchNo}") + public ApiRes mergeApplyDetailInfos(@PathVariable("mchNo") String mchNo) { + + // 指定记录中读取 + String fixApplyId = getValString("fixApplyId"); + + // 当前进件页面操作的 ifCode + String currentPageIfCode = getValString("currentPageIfCode"); + + Class applymentBasicInfoClass = ApplymentBasicInfo.getImplInfoClass(currentPageIfCode); + Assert.notNull(applymentBasicInfoClass, "未知的通道编码[currentPageIfCode]"); + + String mergeIfCode = ""; + + List mergeList = mchApplymentService.list(MchApplyment.gw() + .select(MchApplyment::getIfCode, MchApplyment::getApplyDetailInfo) + .eq(StringUtils.isNotEmpty(fixApplyId), MchApplyment::getApplyId, fixApplyId) + .eq(MchApplyment::getMchNo, mchNo)); + + // 1. 获取到 读取到的列表数据 + for (MchApplyment info : mergeList) { + mergeIfCode = info.getIfCode(); + } + + // 2. 包含fixApplyId 的话, 为:读取副本 操作 && 读取到的和 当前是同一个接口的 + if (StringUtils.isNotEmpty(fixApplyId) && !mergeList.isEmpty() && StringUtils.isNotEmpty(mergeIfCode) && mergeIfCode.equals(currentPageIfCode)) { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(mergeList.get(0).getApplyDetailInfo()); + } catch (Exception e) { + jsonObject = new JSONObject(); + } + jsonObject.put("paywayFeeList", null); // 清空费率信息 + jsonObject.put("uploadImgCache", null); // 清空: 上传图片的缓存信息 + return ApiRes.ok(jsonObject.toJavaObject(applymentBasicInfoClass)); + } + + JSONObject resultJson = new JSONObject(); + // 其他 智能读取 场景 。 + for (MchApplyment info : mergeList) { + if (StringUtils.isNotEmpty(info.getApplyDetailInfo())) { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(info.getApplyDetailInfo()); + } catch (Exception e) { + jsonObject = new JSONObject(); + } + jsonObject.forEach(resultJson::putIfAbsent); + } + } + + // 点击智能读取,mcc,areacode,bankcode因不通用,可不用读取 + resultJson.put("mcc", null); + resultJson.put("areaCode", null); + resultJson.put("payWayFeeList", null); + resultJson.put("uploadImgCache", null); + + return ApiRes.ok(resultJson.toJavaObject(applymentBasicInfoClass)); + } + + + /** + * 首次发起进件申请 + **/ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_ADD')") + @PostMapping + public ApiRes firstApplyment() { + String mchApplyNo = SeqKit.genMchApplyNo(); + MchApplyment mRecord = getObject(MchApplyment.class); + if (mRecord.getRange() == 0 && StrUtil.isEmpty(mRecord.getAutoConfigMchAppId())) { + MchAppEntity offlineApp = mchAppService.getOfflineApp(mRecord.getMchNo()); + Assert.notNull(offlineApp, "线下应用不存在或状态不正常"); + mRecord.setAutoConfigMchAppId(offlineApp.getAppId()); + } + + // 进件来源 + mRecord.setApplyPageType(CS.SYS_ROLE_TYPE.AGENT + "_" + getCurrentUser().getLoginType()); + + // 通用检查项 + commonCheck(mRecord.getApplyId(), mRecord.getIsvNo(), mRecord.getMchNo(), mRecord.getIfCode(), true); + + boolean isTempData = mRecord.extv().getBooleanValue("isTempData"); // 是否保存为草稿 + + MchInfo mchInfo = mchInfoService.getById(mRecord.getMchNo()); + + if (MchInfo.isNotIsv(mchInfo)) { + throw new BizException("请选择特约商户类型"); + } + + MchAppEntity mchApp = mchAppService.getById(mRecord.getAutoConfigMchAppId()); + Assert.notNull(mchApp, "请选择应用"); + + PayInterfaceConfig config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, mRecord.getIsvNo(), mRecord.getIfCode()); + + MchPayInterfaceConfig mchConfig = mchInfoConverter.toMchConfig(config); + mchConfig.setInfoType(CS.SYS_ROLE_TYPE.MCH_APPLYMENT); + mchConfig.setInfoId(mchApplyNo); + MchPayInterfaceConfig exitData = mchPayInterfaceConfigService.get(mchConfig.getInfoType(), mchConfig.getInfoId(), mchConfig.getIfCode()); + if (exitData != null) { + mchConfig.setId(exitData.getId()); + } + mchPayInterfaceConfigService.saveOrUpdate(mchConfig); + + mRecord.setPayInterfaceId(mchConfig.getId()); + + // 校验商户的进件费率 + ApplymentBasicInfo applymentBasicInfo = JSON.parseObject(mRecord.getApplyDetailInfo(), ApplymentBasicInfo.class); + if (applymentBasicInfo != null && applymentBasicInfo.getPaywayFeeList() != null) { + rateConfigService.checkFeeByMch(mRecord.getMchNo(), "", mRecord.getIfCode(), applymentBasicInfo.getPaywayFeeList(), mchApp.getRange(), mchApp.getMccCode(), mRecord.getIsvNo()); + } + + // 设置名称 + mRecord.setIfName(payInterfaceDefineService.getById(mRecord.getIfCode()).getIfName()); + + mRecord.setApplyId(mchApplyNo); //生成申请单号 + if (isTempData) { // 保存草稿 + mRecord.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SAVE); + } else { + // 是否在服务商进件允许的时间范围内 + if (agentConfigService.queryAgentApplymentTimeLimit(getCurrentAgentNo())) { + throw new BizException("当前时间不允许进件,可进件时间范围为:" + agentConfigService.queryAgentApplymentTime(getCurrentAgentNo())); + } + } + + mRecord.setRemainStep((byte) 1); + mRecord.setAgentNo(getCurrentAgentNo()); // 服务商号 + mRecord.setTopAgentNo(agentInfoService.queryTopAgentNo(getCurrentAgentNo())); // 顶级服务商号 + + mRecord.setEpUserId(mchInfo.getCreatedUid()); + mRecord.setCreatedUid(getCurrentUser().getSysUserId()); + mRecord.setCreatedBy(getCurrentUser().getSysUser().getRealname()); + + + transactionTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@NonNull TransactionStatus transactionStatus) { + mchApplymentService.saveOrUpdate(mRecord); + rateConfigService.saveMchApplymentRate(mRecord); + } + }); + + if (isTempData) { // 保存草稿 + return ApiRes.ok(); + } + + // 系统预审环节 + if (agentConfigService.queryAgentApplymentPreAudit(getCurrentAgentNo())) { + MchApplyment auditTbMchApplyment = new MchApplyment(); + auditTbMchApplyment.setApplyId(mRecord.getApplyId()); + auditTbMchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_WAIT_PRE_AUDITING); //系统预审 + mchApplymentService.updateById(auditTbMchApplyment); + return ApiRes.ok(); + } + + // 调起接口 + IIsvmchApplymentService isvmchApplymentService = IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mRecord.getIfCode())); + + MchApplyment applymentResult = new MchApplyment(); + applymentResult.setApplyId(mRecord.getApplyId()); + + // 调起进件接口 + try { + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = isvmchApplymentService.firstApplyment(mchInfoConverter.toModel(mRecord)); + mchInfoConverter.cp(applymentResultByRPC, applymentResult); + + // 更新数据 + applymentResult.setLastApplyAt(new Date()); + mchApplymentService.updateById(applymentResult); + + } catch (Exception e) { + applymentResult.setLastApplyAt(new Date()); + applymentResult.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + applymentResult.setApplyErrorInfo("[" + e.getMessage() + "]"); + mchApplymentService.updateById(applymentResult); + log.info("进件失败:", e); + } + + // 该状态为进件未完成状态,发送数据到消息队列中, + if (applymentResult.getState() == MchApplyment.STATE_AUDITING_WAIT) { + mqSender.send(MchAuditMQ.build(applymentResult.getApplyId())); + } + + // 调起 进件接口 + + // 返回了 审核中, 成功。 失败。 异常的情况认为是: 做失败处理。 异常最好在三方接口处理掉。 + + // 审核中: 页面支持: 【查询最新状态】。 + + // 驳回待修改:【查询最新状态】 【修改进件信息】 --》 修改接口、 补充进件、 重新进件 三选一。 根据上游渠道的不同调起的接口不一样。 接口内部消化吧。 + + // 待验证、 待签约: 全部在备注信息中体现信息。 这种只能手动点击查询接口。 【查询最新状态】 + + // 成功 修改进件信息(优先级低) + + // 失败 按照驳回待修改 + return ApiRes.ok(); + } + + /** + * 修改再次提交进件资料 + **/ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_EDIT')") + @PutMapping("/{recordId}") + public ApiRes rejectModify(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + + if (dbRecord == null + || (dbRecord.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY && dbRecord.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_SAVE && dbRecord.getState() != MchApplyment.STATE_WAIT_PRE_AUDIT_REJECT) + || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("当前申请单状态不是待修改或草稿,无法继续。"); + } + + // 请求参数 + MchApplyment mRecord = getObject(MchApplyment.class); + + MchAppEntity mchApp = mchAppService.getById(mRecord.getAutoConfigMchAppId()); + Assert.notNull(mchApp, "未选择应用"); + + // 通用检查项 + commonCheck(mRecord.getApplyId(), mRecord.getIsvNo(), mRecord.getMchNo(), mRecord.getIfCode(), false); + + boolean isTempData = mRecord.extv().getBooleanValue("isTempData"); // 是否保存为草稿 + + // 校验商户的进件费率 + ApplymentBasicInfo applymentBasicInfo = JSON.parseObject(mRecord.getApplyDetailInfo(), ApplymentBasicInfo.class); + if (applymentBasicInfo != null && applymentBasicInfo.getPaywayFeeList() != null) { + rateConfigService.checkFeeByMch(mRecord.getMchNo(), "", mRecord.getIfCode(), applymentBasicInfo.getPaywayFeeList(), mchApp.getRange(), mchApp.getMccCode(), mRecord.getIsvNo()); + } + + transactionTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@NonNull TransactionStatus transactionStatus) { + mchApplymentService.saveOrUpdate(mRecord); + rateConfigService.saveMchApplymentRate(mRecord); + } + }); + + if (isTempData) { + mRecord.setApplyId(recordId); + mchApplymentService.updateById(mRecord); + return ApiRes.ok(); + } + + // 是否在服务商进件允许的时间范围内 + if (agentConfigService.queryAgentApplymentTimeLimit(getCurrentAgentNo())) { + throw new BizException("当前时间不允许进件,可进件时间范围为:" + agentConfigService.queryAgentApplymentTime(getCurrentAgentNo())); + } + + MchInfo mchInfo = mchInfoService.getById(mRecord.getMchNo()); + + if (MchInfo.isNotIsv(mchInfo)) { + throw new BizException("请选择特约商户类型"); + } + + // 预审核失败的修改 --> 待审核 + if (dbRecord.getState() == MchApplyment.STATE_WAIT_PRE_AUDIT_REJECT) { + + mRecord.setApplyId(recordId); + mRecord.setApplyErrorInfo(""); + mRecord.setState(MchApplyment.STATE_WAIT_PRE_AUDITING); + mRecord.setUpdatedAt(new Date()); + mchApplymentService.updateById(mRecord); + return ApiRes.ok(); + } + + // 更新DB数据, 重新发起申请 + mRecord.setState(MchApplyment.STATE_AUDITING); // 保存状态 + mRecord.setRemainStep((byte) 1); + mRecord.setApplyErrorInfo(""); //清空错误信息 + mchApplymentService.update(mRecord, Wrappers.lambdaQuery(MchApplyment.class).eq(MchApplyment::getApplyId, recordId).in(MchApplyment::getState, + Arrays.asList(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SAVE, com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY))); + rateConfigService.saveMchApplymentRate(mRecord); + IIsvmchApplymentService isvMchApplymentService = IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mRecord.getIfCode())); + // 重新获取最新数据 + dbRecord = mchApplymentService.getById(recordId); + + PayInterfaceConfig config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, mRecord.getIsvNo(), mRecord.getIfCode()); + + MchPayInterfaceConfig mchConfig = mchInfoConverter.toMchConfig(config); + mchConfig.setInfoType(CS.SYS_ROLE_TYPE.MCH_APPLYMENT); + mchConfig.setInfoId(mRecord.getApplyId()); + MchPayInterfaceConfig exitData = mchPayInterfaceConfigService.get(mchConfig.getInfoType(), mchConfig.getInfoId(), mchConfig.getIfCode()); + if (exitData != null) { + mchConfig.setId(exitData.getId()); + } + mchPayInterfaceConfigService.saveOrUpdate(mchConfig); + + // 调起进件接口 + MchApplyment applymentResult = new MchApplyment(); + applymentResult.setApplyId(mRecord.getApplyId()); + + // 调起进件接口 + try { + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = isvMchApplymentService.rejectModify(mchInfoConverter.toModel(dbRecord)); + BeanUtils.copyProperties(applymentResultByRPC, applymentResult); + + // 更新数据 + applymentResult.setApplyId(mRecord.getApplyId()); + applymentResult.setLastApplyAt(new Date()); + mchApplymentService.updateById(applymentResult); + } catch (Exception e) { + // 异步请求的异常 + applymentResult.setLastApplyAt(new Date()); + applymentResult.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + applymentResult.setApplyErrorInfo("[" + e.getMessage() + "]"); + mchApplymentService.updateById(applymentResult); + log.info("进件失败:", e); + } + + // 该状态为进件未完成状态,发送数据到消息队列中, + if (applymentResult.getState() == MchApplyment.STATE_AUDITING_WAIT) { + mqSender.send(MchAuditMQ.build(applymentResult.getApplyId())); + } + + return ApiRes.ok(); + } + + + /** + * 进件参数的配置 + **/ + @PostMapping("/appConfig/{applyId}/{mchAppId}") + public ApiRes configApp(@PathVariable("applyId") String applyId, @PathVariable("mchAppId") String mchAppId) { + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + if (tbMchApplyment == null || tbMchApplyment.getState() != MchApplyment.STATE_SUCCESS || !tbMchApplyment.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("进件不存在或状态不正确"); + } + + if (StringUtils.isEmpty(tbMchApplyment.getSuccResParameter())) { + throw new BizException("不存在进件支付参数,请手动配置"); + } + + + PayInterfaceConfig updateRecord = new PayInterfaceConfig(); + updateRecord.setIfParams(tbMchApplyment.getSuccResParameter()); + + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, mchAppId, tbMchApplyment.getIfCode()); + + if (payInterfaceConfig != null) { + updateRecord.setId(payInterfaceConfig.getId()); + payInterfaceConfigService.updateById(updateRecord); + } else { + + updateRecord.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP); + updateRecord.setInfoId(mchAppId); + updateRecord.setIfCode(tbMchApplyment.getIfCode()); + payInterfaceConfigService.save(updateRecord); + + } + + return ApiRes.ok(); + } + + + /** + * 查询其他配置信息(如支付目录, 渠道商微信公众号APPID) + **/ + @GetMapping("/interfaceConfig/{applyId}") + public ApiRes selectInterfaceConfig(@PathVariable("applyId") String applyId) { + + String isvNo = null; + + // 查询选择的OAuth2 信息 + String selectOauth2InfoId = null; + + // 根据appID 查询 +// if (getValByteDefault("applyIdConvertMchAppId", CS.NO) == CS.YES) { +// MchInfo mchInfo = mchInfoService.getById(mchAppService.getById(applyId).getMchNo()); +// isvNo = mchInfo.getIsvNo(); +// selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(mchInfo, getValString("convertMchAppIfCode")); +// +// } else { +// +// MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); +// isvNo = tbMchApplyment.getIsvNo(); +// selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(tbMchApplyment.getAgentNo(), isvNo, tbMchApplyment.getIfCode()); +// } + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + isvNo = tbMchApplyment.getIsvNo(); + selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(tbMchApplyment.getAgentNo(), isvNo, tbMchApplyment.getIfCode()); + + String paySiteUrl = sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + + WxpayOauth2Params wxpayOauth2Params = configContextQueryService.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, StringUtils.defaultIfEmpty(selectOauth2InfoId, isvNo), CS.IF_CODE.WXPAY, WxpayOauth2Params.class); + + JSONObject result = new JSONObject(); + String appId = ""; + String liteAppId = ""; + if (wxpayOauth2Params != null) { + appId = wxpayOauth2Params.getAppId(); + liteAppId = wxpayOauth2Params.getLiteAppId(); + } + result.put("paySiteUrl", paySiteUrl); + result.put("wxAppId", appId); + result.put("wxLiteAppId", liteAppId); + return ApiRes.ok(result); + } + + + /** + * 配置相关信息 + **/ + @PostMapping("/interfaceConfig/{applyId}/{mchAppId}") + public ApiRes configInterfaceConfig(@PathVariable("applyId") String applyId, @PathVariable("mchAppId") String mchAppId) { + + String configType = getValStringRequired("configType"); // PAY_BASE_URL, BIND_APP_ID, SUBSCRIBE_APP_ID + String configVal = getValStringRequired("configVal"); + + MchAppEntity mchAppEntity = mchAppService.getById(mchAppId); + String mchNo = mchAppEntity.getMchNo(); + + String ifCode = null; + String isvNo = null; + + // 商户应用的 渠道配置页面 && 传输过的是ifCode + String appConfigModeAndIfCode = getValString("appConfigModeAndIfCode"); + +// if (StringUtils.isNotEmpty(appConfigModeAndIfCode)) { +// ifCode = appConfigModeAndIfCode; +// isvNo = mchInfoService.getById(mchNo).getIsvNo(); +// +// } else { // 原逻辑 +// +// MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); +// ifCode = tbMchApplyment.getIfCode(); +// isvNo = tbMchApplyment.getIsvNo(); +// } + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + ifCode = tbMchApplyment.getIfCode(); + isvNo = tbMchApplyment.getIsvNo(); + + IIsvmchWxConfigService isvMchWxConfigService = IsvFactory.getIsvMchWxConfigService(JeepayKit.getIfCodeOrigin(ifCode)); + + if ("PAY_BASE_URL".equals(configType)) { // 微信支付目录 + + return ApiRes.ok(isvMchWxConfigService.configPayBaseUrl(configVal, isvNo, mchNo, mchAppId, ifCode)); + + } + if ("QUERY".equals(configType)) { + + return ApiRes.ok(isvMchWxConfigService.queryConfiguredInfo(isvNo, mchNo, mchAppId, ifCode)); + + } else if ("BIND_APP_ID".equals(configType)) { // 关联微信各种appId: + + return ApiRes.ok(isvMchWxConfigService.configBindAppId(configVal, isvNo, mchNo, mchAppId, ifCode)); + + } else if ("SUBSCRIBE_APP_ID".equals(configType)) { // 支付成功关注公众号 + + return ApiRes.ok(isvMchWxConfigService.configSubscribeAppId(configVal, isvNo, mchNo, mchAppId, ifCode)); + + } else if ("MCH_SHORT_NAME".equals(configType)) { // 修改商户名称 + + return ApiRes.ok(isvMchWxConfigService.applyModifyMchShortName(configVal, isvNo, mchNo, mchAppId, ifCode)); + } else if ("MCH_APP_PUBLIC_KEY".equals(configType)) { // 设置子商户公钥(目前仅盛付通使用) + + return ApiRes.ok(isvMchWxConfigService.applyModifyMchAppPublicKey(configVal, isvNo, mchNo, mchAppId, ifCode)); + + } else if ("MCH_STORE_ADD".equals(configType)) { // 门店配置(目前仅河马渠道使用) + hmpaySubMchParamsModify(configVal, mchNo, mchAppId); + return ApiRes.ok(ChannelRetMsg.confirmSuccess(null)); + + } else if ("MCH_RATE_UPDATE".equals(configType)) { // 费率修改 + + List list = JSON.parseArray(configVal, PaywayFee.class); + return ApiRes.ok(isvMchWxConfigService.applyModifyMchRate(list, isvNo, mchNo, mchAppId, ifCode)); + } + + return ApiRes.customFail("没有[" + configType + "]配置"); + } + + + /** + * 预先校验当前商户是否可完成该通道的进件 + **/ + @GetMapping("/applyPreCheck/{mchNo}/{ifCode}") + public ApiRes applyPreCheck(@PathVariable("mchNo") String mchNo, @PathVariable("ifCode") String ifCode) { + String isvNo = getValStringRequired("isvNo"); + commonCheck(null, isvNo, mchNo, ifCode, true); + return ApiRes.ok(); + } + + /** + * 门店入驻 + **/ + @PostMapping("/storeApplyment/{storeId}/{state}/{recordId}") + public ApiRes storeApplyment(@PathVariable("storeId") String storeId, @PathVariable("state") Byte state, @PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前申请单状态不是成功,无法继续。"); + } + MchStore mchStore = mchStoreService.getById(storeId); + if (mchStore == null) { + throw new BizException("所选门店不存在。"); + } + if (StringUtils.isEmpty(mchStore.getStoreOuterImg()) || StringUtils.isEmpty(mchStore.getStoreInnerImg()) || + mchStore.getAreaCode() == null || StringUtils.isEmpty(mchStore.getStoreLogo()) || StringUtils.isEmpty(mchStore.getContactPhone())) { + throw new BizException("所选门店信息不完整,请先将门店信息填写完整再发起入驻申请。"); + } + + IIsvmchStoreApplymentService isvmchStoreApplymentService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "MchStoreApplymentService", IIsvmchStoreApplymentService.class); + + // 调起进件接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = null; + if (MchApplyment.STATE_AUDITING == state) { + throw new BizException("门店正在审核中"); + } + + if (MchApplyment.STATE_REJECT_WAIT_MODIFY == state) { + // 驳回待修改 + applymentResultByRPC = isvmchStoreApplymentService.storeApplymentModify(mchInfoConverter.toModel(dbRecord), mchStore, getReqParamJSON()); + } else { + applymentResultByRPC = isvmchStoreApplymentService.firstStoreApplyment(mchInfoConverter.toModel(dbRecord), mchStore); + } + MchApplyment applymentResult = new MchApplyment(); + BeanUtils.copyProperties(applymentResultByRPC, applymentResult); + applymentResult.setApplyId(recordId); + // 状态不为失败时进行更新 + if (applymentResult.getState() != MchApplyment.STATE_REJECT_WAIT_MODIFY) { + // db门店入驻信息 + String storeSuccResParameter = dbRecord.getStoreSuccResParameter(); + JSONArray jsonArray = new JSONArray(); + JSONArray arrayStore = getJSONArrayStore(jsonArray, storeSuccResParameter, storeId, applymentResult); + + applymentResult.setStoreSuccResParameter(arrayStore.toJSONString()); + // 不更新进件状态、渠道单号 + applymentResult.setState(null); + applymentResult.setChannelApplyNo(null); + // 更新数据 + mchApplymentService.updateById(applymentResult); + } + return ApiRes.ok(); + } + + /** + * 河马付门店入驻查询 + **/ + @GetMapping("/storeApplyment/{recordId}") + public ApiRes storeApplymentQuery(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前申请单状态不是成功,无法继续。"); + } + + // db入驻详情 + MchApplyment record = mchApplymentService.getById(recordId); + + IIsvmchStoreApplymentService isvmchStoreApplymentService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(record.getIfCode()) + "MchStoreApplymentService", IIsvmchStoreApplymentService.class); + + // 调起门店查询接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = isvmchStoreApplymentService.storeApplymentQuery(mchInfoConverter.toModel(dbRecord)); + + if (applymentResultByRPC == null) { + return ApiRes.ok(); + } + + try { + MchApplyment applymentResult = new MchApplyment(); + applymentResult.setApplyId(recordId); + applymentResult.setStoreSuccResParameter(applymentResultByRPC.getStoreSuccResParameter()); + if (StringUtils.isNotEmpty(applymentResultByRPC.getSuccResParameter())) { + applymentResult.setSuccResParameter(applymentResultByRPC.getSuccResParameter()); + } + // 更新数据 + mchApplymentService.updateById(applymentResult); + } catch (Exception e) { + logger.error("门店入驻更新数据库门店信息失败,申请单号{}", recordId); + } + + return ApiRes.ok(applymentResultByRPC.getStoreSuccResParameter()); + } + + public static JSONArray getJSONArrayStore(JSONArray jsonArray, String storeSuccResParameter, String storeId, MchApplyment applymentResult) { + if (StringUtils.isEmpty(storeSuccResParameter)) { + JSONObject storeJson = new JSONObject(); + storeJson.put("storeId", storeId); + storeJson.put("store_no", applymentResult.getChannelApplyNo()); + storeJson.put("state", applymentResult.getState()); + jsonArray.add(storeJson); + applymentResult.setStoreSuccResParameter(jsonArray.toJSONString()); + } else { + jsonArray = JSON.parseArray(storeSuccResParameter); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject json = (JSONObject) jsonArray.get(i); + if (storeId.equals(json.getString("storeId")) && applymentResult.getChannelApplyNo().equals(json.getString("store_no"))) { + jsonArray.remove(i); + break; + } + } + JSONObject storeJson = new JSONObject(); + storeJson.put("storeId", storeId); + storeJson.put("store_no", applymentResult.getChannelApplyNo()); + storeJson.put("state", applymentResult.getState()); + jsonArray.add(storeJson); + } + return jsonArray; + } + + /** + * 动态获取微信收付通 银行支行列表 + **/ + @GetMapping("/bankList/{mchNo}/{ifCode}/{isvNo}") + public ApiRes bankList(@PathVariable("mchNo") String mchNo + , @PathVariable("ifCode") String ifCode + , @PathVariable("isvNo") String isvNo) { + + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (MchInfo.isNotIsv(mchInfo)) { + throw new BizException("请选择特约商户类型"); + } + + String bankAliasCode = getValString("bankAliasCode"); + String cityCode = getValStringRequired("cityCode"); + String bankName = getValString("bankName"); + String branchName = getValString("branchName"); + + IGetApplymentDataService getApplymentDataService = IsvFactory.getGetApplymentDataService(JeepayKit.getIfCodeOrigin(ifCode)); + try { + // 调起接口 + List list = getApplymentDataService.getBankBranchInfo(isvNo, bankAliasCode, cityCode, bankName, branchName); + + return ApiRes.ok(list); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + } + + + /** + * 通用校验: 商户 / 商户类型 / 服务商 / 渠道商 / 接口开关 / 渠道商参数配置开关 + **/ + private void commonCheck(String applyId, String isvNo, String mchNo, String ifCode, boolean checkHasRecord) { + + MchInfo mchInfo = mchInfoService.getById(mchNo); + + if (!ObjUtil.isEmpty(applyId)) { + MchApplyment existData = mchApplymentService.getById(applyId); + if (existData.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_SAVE + && existData.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY + && existData.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_WAIT_PRE_AUDIT_REJECT) { + throw new BizException("当前商户状态不支持该操作"); + } + } + + if (mchInfo == null || mchInfo.getState() != CS.YES) { + throw new BizException("当前商户不可用"); + } + + if (!Objects.equals(mchInfo.getAgentNo(), getCurrentAgentNo())) { + throw new BizException("该商户不是您名下的商户"); + } + + if (isvNo == null) { + throw new BizException("请选择特约商户"); + } + + IsvInfoEntity isvInfoEntity = isvInfoService.getById(isvNo); + if (isvInfoEntity == null || !isvInfoEntity.getState().equals(CS.YES)) { + throw new BizException("当前渠道商不可用"); + } + + AgentInfo agentInfo = agentInfoService.getById(mchInfo.getAgentNo()); + if (agentInfo == null || !agentInfo.getState().equals(CS.YES)) { + throw new BizException("当前服务商不可用"); + } + + PayInterfaceDefine payInterfaceDefine = payInterfaceDefineService.getById(ifCode); + if (payInterfaceDefine == null || !payInterfaceDefine.getState().equals(CS.YES)) { + throw new BizException("当前支付接口不可用"); + } + if (payInterfaceDefine.getIsSupportApplyment() != CS.YES || payInterfaceDefine.getIsOpenApplyment() != CS.YES) { + throw new BizException("当前支付接口不支持或未开启进件"); + } + + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, isvInfoEntity.getIsvNo(), ifCode); + + if (payInterfaceConfig == null || payInterfaceConfig.getState() != CS.YES) { + throw new BizException("当前渠道商支付接口配置不可用"); + } + + if (checkHasRecord) { + // 20220708 允许一个商户进件多次的情况 +// int count = mchApplymentService.count(MchApplyment.gw().eq(MchApplyment::getMchNo, mchNo).eq(MchApplyment::getIfCode, ifCode)); +// if(count > 0 ){ +// throw new BizException("该商户在当前通道已存在进件数据,不可再次发起"); +// } + } + } + + /** + * @author: xiaoyu + * @date: 2022/4/24 9:47 + * @describe: 河马付门店参数绑定 + */ + public void hmpaySubMchParamsModify(String configVal, String mchNo, String mchAppId) { + try { + + MchApplyment tbMchApplyment = JSON.parseObject(configVal, MchApplyment.class); + if (tbMchApplyment == null || StringUtils.isEmpty(tbMchApplyment.getChannelApplyNo())) { + throw new BizException("参数为空!mchApplyment=" + tbMchApplyment); + } + if (StringUtils.isEmpty(tbMchApplyment.getStoreSuccResParameter())) { + throw new BizException("门店信息为空!mchApplyment=" + tbMchApplyment); + } + + HmpayIsvsubMchParams hmpayIsvsubMchParams = (HmpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchNo, mchAppId, CS.IF_CODE.HMPAY); + if (hmpayIsvsubMchParams == null) { + hmpayIsvsubMchParams = new HmpayIsvsubMchParams(); + } + PayInterfaceConfig updateRecord = new PayInterfaceConfig(); + // 门店信息 + hmpayIsvsubMchParams.setMchStoreConfig(tbMchApplyment.getStoreSuccResParameter()); + // 子商户号 + if (StringUtils.isEmpty(hmpayIsvsubMchParams.getSubAppId())) { + hmpayIsvsubMchParams.setSubAppId(tbMchApplyment.getChannelApplyNo()); + } + updateRecord.setIfParams(hmpayIsvsubMchParams.getJsonParams().toString()); + + // 接口配置 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, mchAppId, tbMchApplyment.getIfCode()); + + if (payInterfaceConfig != null) { + updateRecord.setId(payInterfaceConfig.getId()); + payInterfaceConfigService.updateById(updateRecord); + } else { + + updateRecord.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP); + updateRecord.setInfoId(mchAppId); + updateRecord.setIfCode(tbMchApplyment.getIfCode()); + payInterfaceConfigService.save(updateRecord); + + } + + } catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 富友 电子协议生成 + **/ + @PostMapping("/elecContractGenerate/{recordId}") + public ApiRes elecContractGenerate(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = fuiouApplymentApiService.elecContractGenerate(mchInfoConverter.toModel(dbRecord)); + + MchApplyment updateRecord = new MchApplyment(); + BeanUtils.copyProperties(applymentResult, updateRecord); + + // 更新数据 + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(mchApplymentService.getById(recordId)); + } + + /** + * 富友 电子协议签署 + **/ + @PostMapping("/elecContractSign/{recordId}") + public ApiRes elecContractSign(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("当前申请单状态不是待签约,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = fuiouApplymentApiService.elecContractSign(mchInfoConverter.toModel(dbRecord)); + + MchApplyment updateRecord = new MchApplyment(); + BeanUtils.copyProperties(applymentResult, updateRecord); + + // 更新数据 + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(); + } + + /** + * 富友 上传图片 + **/ + @PostMapping("/fuiouUpload/{recordId}") + public ApiRes fuiouUpload(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && + dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + boolean result = fuiouApplymentApiService.uploadImg(mchInfoConverter.toModel(dbRecord)); + if (!result) { + return ApiRes.customFail("图片上传失败"); + } + + // 上传成功,提交审核 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = fuiouApplymentApiService.attachConfirm(mchInfoConverter.toModel(dbRecord)); + + MchApplyment updateRecord = new MchApplyment(); + BeanUtils.copyProperties(applymentResult, updateRecord); + + // 更新数据 + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(); + } + + /** + * 富友 提交审核 + **/ + @PostMapping("/fuiouConfirm/{recordId}") + public ApiRes fuiouConfirm(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && + dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = fuiouApplymentApiService.attachConfirm(mchInfoConverter.toModel(dbRecord)); + + MchApplyment updateRecord = new MchApplyment(); + mchInfoConverter.cp(applymentResult, updateRecord); + + // 更新数据 + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(); + } + + /** + * 富友 富友微信参数配置 + **/ + @PostMapping("/fuiouWxConfigSet/{recordId}") + public ApiRes fuiouWxConfigSet(@PathVariable("recordId") String recordId) { + + String jsapiPath = getValString("configWxPayBaseUrl"); + String subAppid = getValString("configWxBindAppId"); + String subscribeAppid = getValString("configWxSubscribeAppId"); + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_AUDITING + && dbRecord.getState() != MchApplyment.STATE_SUCCESS && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + fuiouApplymentApiService.wechatConfigSet(mchInfoConverter.toModel(dbRecord), jsapiPath, subAppid, subscribeAppid); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(); + } + + /** + * 富友 获取微信参数配置 + **/ + @PostMapping("/fuiouWxConfigGet/{recordId}") + public ApiRes fuiouWxConfigGet(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY + && dbRecord.getState() != MchApplyment.STATE_SUCCESS && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IFuiouApplymentApiService fuiouApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IFuiouApplymentApiService.class); + + try { + // 调起接口 + String wechatConfig = fuiouApplymentApiService.wechatConfigGet(mchInfoConverter.toModel(dbRecord)); + return ApiRes.ok(JSON.parseObject(wechatConfig)); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + } + + /** + * 斗拱 分账配置 + **/ + @PostMapping("/dgpayConfigOpen/{recordId}") + public ApiRes dgpayConfigOpen(@PathVariable("recordId") String recordId) { + JSONObject paramJSON = getReqParamJSON(); + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY + && dbRecord.getState() != MchApplyment.STATE_SUCCESS && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IDgApplymentApiService dgApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IDgApplymentApiService.class); + try { + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = dgApplymentApiService.dgpayConfigOpen(mchInfoConverter.toModel(dbRecord), paramJSON); + // 状态未改为待验证 则抛出错误信息 + if (StringUtils.isNotEmpty(mchApplyment.getApplyErrorInfo())) { + return ApiRes.customFail(mchApplyment.getApplyErrorInfo()); + } + // 更新数据 + MchApplyment updateRecord = new MchApplyment(); + updateRecord.setApplyId(recordId); + updateRecord.setChannelVar1(mchApplyment.getChannelVar1()); + mchApplymentService.updateById(updateRecord); + return ApiRes.ok(); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + } + + /** + * 斗拱 分账配置查询 + **/ + @GetMapping("/dgpayConfigOpenQuery/{recordId}") + public ApiRes dgpayConfigOpenQuery(@PathVariable("recordId") String recordId) { + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY + && dbRecord.getState() != MchApplyment.STATE_SUCCESS && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IDgApplymentApiService dgApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IDgApplymentApiService.class); + try { + + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = dgApplymentApiService.dgpayConfigOpenQuery(mchInfoConverter.toModel(dbRecord)); + // 状态未改为待验证 则抛出错误信息 + if (StringUtils.isNotEmpty(mchApplyment.getApplyErrorInfo())) { + return ApiRes.customFail(mchApplyment.getApplyErrorInfo()); + } + return ApiRes.ok(mchApplyment.getChannelVar2()); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + } + + /** + * 斗拱 微信参数配置 + **/ + @PostMapping("/dgWxConfigSet/{recordId}") + public ApiRes dgWxConfigSet(@PathVariable("recordId") String recordId) { + + String feeType = getValString("feeType"); + String jsapiPath = getValString("configWxPayBaseUrl"); + String configWxBindLiteAppId = getValString("configWxBindLiteAppId"); + String configWxBindAppId = getValString("configWxBindAppId"); + String bankChannelNo = getValString("bankChannelNo"); + String isvNo = getValStringRequired("isvNo"); + + // 商户应用的 渠道配置页面 && 传输过的是ifCode + String appConfigModeAndIfCode = getValString("appConfigModeAndIfCode"); + + MchAppEntity mchAppEntity = mchAppService.getById(recordId); + String mchNo = mchAppEntity.getMchNo(); + + String ifCode = appConfigModeAndIfCode; + + IDgApplymentApiService dgApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "ApplymentApiService", IDgApplymentApiService.class); + + try { + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = dgApplymentApiService.wechatConfigSet(isvNo, mchNo, recordId, jsapiPath, feeType, configWxBindLiteAppId, configWxBindAppId, bankChannelNo, ifCode); + if (mchApplyment.getState() == null || com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS != mchApplyment.getState()) { + return ApiRes.customFail(mchApplyment.getApplyErrorInfo()); + } + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + return ApiRes.ok(); + } + + /** + * 斗拱 开通业务 + **/ + @PostMapping("/dgpayWxRealName/{recordId}") + public ApiRes dgpayWxRealName(@PathVariable("recordId") String recordId) { + JSONObject paramJSON = getReqParamJSON(); + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY + && dbRecord.getState() != MchApplyment.STATE_SUCCESS && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IDgApplymentApiService dgApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IDgApplymentApiService.class); + + try { + dbRecord.setApplyDetailInfo(paramJSON.toString()); + + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = dgApplymentApiService.wechatRealName(mchInfoConverter.toModel(dbRecord)); + // 状态未改为待验证 则抛出错误信息 + if (mchApplyment.getState() == null || com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS != mchApplyment.getState()) { + return ApiRes.customFail(mchApplyment.getApplyErrorInfo()); + } + // 微信申请单号 + String applymentId = mchApplyment.getChannelApplyNo(); + paramJSON.put("applymentId", applymentId); + // 更新数据 + MchApplyment updateRecord = new MchApplyment(); + updateRecord.setApplyDetailInfo(paramJSON.toString()); + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + return ApiRes.ok(); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + } + + /** + * 乐刷 开通业务 + **/ + @PostMapping("/leshuapayConfigOpen/{recordId}") + public ApiRes leshuapayConfigOpen(@PathVariable("recordId") String recordId) { + JSONObject paramJSON = getReqParamJSON(); + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_SUCCESS)) { + throw new BizException("当前申请单状态错误,无法继续,只有进件成功,才能进行业务开通。"); + } + ILeshuaApplymentApiService leshuaApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", ILeshuaApplymentApiService.class); + try { + dbRecord.setApplyDetailInfo(paramJSON.toString()); + com.jeequan.jeepay.core.entity.MchApplyment mchApplyment = leshuaApplymentApiService.leshuapayConfigOpen(mchInfoConverter.toModel(dbRecord)); + // 更新数据 + MchApplyment updateRecord = new MchApplyment(); + BeanUtils.copyProperties(mchApplyment, updateRecord); + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + return ApiRes.ok(); + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + } + + /** + * 进件参数的配置 + **/ + @PostMapping("/lklAppConfig/{applyId}/{mchAppId}") + public ApiRes configAppInfo(@PathVariable("applyId") String applyId, @PathVariable("mchAppId") String mchAppId) { + JSONObject paramJSON = getReqParamJSON(); + // 拉卡拉商户号 + String merCupNo = paramJSON.getString("merCupNo"); + // 终端号 + String termNo = paramJSON.getString("termNo"); + // 微信子商户号 + String subMchId = paramJSON.getString("subMchId"); + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + if (tbMchApplyment == null || tbMchApplyment.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("进件不存在或状态不正确"); + } + + if (StringUtils.isEmpty(tbMchApplyment.getSuccResParameter())) { + throw new BizException("不存在进件支付参数,请手动配置"); + } + + JSONObject paramsJson = new JSONObject(); + if (StringUtils.isNotEmpty(merCupNo)) { + paramsJson.put("merCupNo", merCupNo); + } + if (StringUtils.isNotEmpty(subMchId)) { + paramsJson.put("subMchId", subMchId); + } + if (StringUtils.isNotEmpty(termNo)) { + paramsJson.put("termNo", termNo); + } + + PayInterfaceConfig updateRecord = new PayInterfaceConfig(); + + if (StringUtils.isNotEmpty(merCupNo) || StringUtils.isNotEmpty(subMchId) || StringUtils.isNotEmpty(termNo)) { + updateRecord.setIfParams(paramsJson.toJSONString()); + } else { + updateRecord.setIfParams(tbMchApplyment.getSuccResParameter()); + } + + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, mchAppId, tbMchApplyment.getIfCode()); + + if (payInterfaceConfig != null) { + updateRecord.setId(payInterfaceConfig.getId()); + payInterfaceConfigService.updateById(updateRecord); + } else { + + updateRecord.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP); + updateRecord.setInfoId(mchAppId); + updateRecord.setIfCode(tbMchApplyment.getIfCode()); + payInterfaceConfigService.save(updateRecord); + + } + + return ApiRes.ok(); + } + + /** + * 银联前置 新增支付类型 + **/ + @PostMapping("/payConf/{recordId}") + public ApiRes payConfAdd(@PathVariable("recordId") String recordId) { + + JSONObject reqParamJSON = getReqParamJSON(); + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_REJECT_WAIT_MODIFY + && dbRecord.getState() != MchApplyment.STATE_SUCCESS)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IUtmpayApplymentApiService applymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IUtmpayApplymentApiService.class); + + String channelApplyNo = dbRecord.getChannelApplyNo(); + + // 调起接口 + ChannelRetMsg channelRetMsg = applymentApiService.mchPayConfAdd(reqParamJSON, dbRecord.getIsvNo(), dbRecord.getMchNo(), channelApplyNo); + + if (channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) { + return ApiRes.ok(channelRetMsg.getChannelOrderId()); + } else { + return ApiRes.customFail(channelRetMsg.getChannelErrMsg()); + } + + } + + /** + * 银联前置 查询第三方交易识别码 + **/ + @PostMapping("/mchPartner/{recordId}/{mchAppId}") + public ApiRes getMchPartner(@PathVariable("recordId") String recordId, @PathVariable("mchAppId") String mchAppId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_SUCCESS) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + + IUtmpayApplymentApiService applymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IUtmpayApplymentApiService.class); + + // String apiCode = getValStringRequired("apiCode"); + + // 调起接口 + ChannelRetMsg channelRetMsg = applymentApiService.getMchPartner(UtmpayConfig.WX_API_CODE, dbRecord.getIsvNo(), dbRecord.getMchNo(), mchAppId); + + if (channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) { + return ApiRes.ok(JSON.parseObject(channelRetMsg.getChannelOrderId())); + } else { + return ApiRes.customFail(channelRetMsg.getChannelErrMsg()); + } + + } + + /** + * 获取银行编码 + **/ + @GetMapping("/bankCode/{ifCode}") + public ApiRes getBankCode(@PathVariable("ifCode") String ifCode) { + + JSONObject queryParams = getReqParamJSON(); + + IApplymentResourceService applymentResourceService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "ApplymentResourceService", IApplymentResourceService.class); + + IPage page = applymentResourceService.getBankCode(getIPage(), queryParams); + + return ApiRes.page(page); + } + + /** + * 进件类 继承自IApplymentResourceService + * type 自定义业务种类 获取商户号和json数据对象进行特定操作 + * 现用于:国通星驿付安心签签署 + **/ + @PostMapping("iApplyRes/sendPubRequst/{ifCode}") + public ApiRes sendPubRequst(@PathVariable("ifCode") String ifCode) { + // 获取业务类型,用于前端调一个接口可执行不同的逻辑 不必传 + String type = getValString("operationType"); + // 获取当前商户信息 + String mchNo = getValStringRequired("mchNo"); + String applyId = getValString("applyId"); + String jsonStr = getValStringRequired("jsonStr"); + IApplymentResourceService applymentResourceService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "ApplymentResourceService", IApplymentResourceService.class); + return ApiRes.ok(applymentResourceService.sendPubRequst(type, mchNo, applyId, jsonStr)); + } + + /** + * 进件api + **/ + @PostMapping("/applymentNextBiz/{applyId}") + public ApiRes applymentNextBiz(@PathVariable("applyId") String applyId) { + String method = getValStringRequired("method"); + JSONObject paramJSON = getReqParamJSON(); + + try { + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + + IApplymentApiService applymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(tbMchApplyment.getIfCode()) + "ApplymentApiService", IApplymentApiService.class); + com.jeequan.jeepay.core.entity.MchApplyment applymentResultByRPC = applymentApiService.entry(method, mchInfoConverter.toModel(tbMchApplyment), paramJSON); + + // 更新数据 + MchApplyment applymentResult = new MchApplyment(); + BeanUtils.copyProperties(applymentResultByRPC, applymentResult); + applymentResult.setApplyId(applyId); + mchApplymentService.updateById(applymentResult); + + return ApiRes.ok(applymentResult); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 获取渠道商渠道配置参数 + **/ + @GetMapping("/getIsvChannelConfig/{mchNo}/{ifCode}/{isvNo}") + public ApiRes applyPregetIsvChannelConfigCheck(@PathVariable("mchNo") String mchNo + , @PathVariable("ifCode") String ifCode, @PathVariable("isvNo") String isvNo) { + + // 已过校验,跳过校验步骤 + + // 渠道商信息 + IsvInfoEntity isvInfoEntity = isvInfoService.getById(isvNo); + // 渠道配置 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, isvInfoEntity.getIsvNo(), ifCode); + // 返回渠道配置参数 + IsvChannelConfig channelConfig = JSON.parseObject(payInterfaceConfig.getIfParams(), IsvChannelConfig.class); + + return ApiRes.ok(channelConfig); + } + + /** + * 进件数据变更 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_ADD')") + @PostMapping("/modifyApplyment") + public ApiRes modifyApplyment() { + + String operationType = getValString("operationType"); + MchModifyApplymentModel reqModel = getObject(MchModifyApplymentModel.class); + Assert.notNull(reqModel.getMchApplyId(), "缺少商户编号[mchApplyId]"); + Assert.notNull(reqModel.getModifyApplyType(), "缺少变更类型[modifyApplyType]"); + + if (!"1".equals(operationType) && !"2".equals(operationType)) { + throw new BizException("非法的操作类型[operationType]"); + } + + MchApplyment mchApplyment = mchApplymentService.getById(reqModel.getMchApplyId()); + Assert.notNull(mchApplyment, "未获取到商户信息"); + + switch (reqModel.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + Assert.isTrue(!CharSequenceUtil.isEmpty(reqModel.getMchShortName()), "商户简称[mchShortName]不能为空"); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + Assert.notNull(reqModel.getSettAccountType(), "结算账户类型[settleAccountType]不能为空"); + Assert.notNull(reqModel.getIllegal(), "结算类型[illegal]不能为空"); + Assert.notNull(reqModel.getSettAccountNo(), "结算账户号[settAccountNo]不能为空"); + + if ("Y".equals(reqModel.getIllegal())) { + Assert.notNull(reqModel.getSettAccountName(), "结算账户名称[settAccountName]不能为空"); + Assert.notNull(reqModel.getSettAccountIdcardNo(), "结算人身份证号[settAccountIdcardNo]不能为空"); + Assert.notNull(reqModel.getSettAccountIdcard1Img(), "结算人身份证卡号面图片[settAccountIdcard1Img]不能为空"); + Assert.notNull(reqModel.getSettAccountIdcard2Img(), "结算人身份证国徽面图片[settAccountIdcard2Img]不能为空"); + Assert.notNull(reqModel.getSettAccountIdcardEffectBegin(), "结算人身份证有效期开始时间[settAccountIdcardEffectBegin]不能为空"); + Assert.notNull(reqModel.getSettAccountIdcardEffectEnd(), "结算人身份证有效期截止时间[settAccountIdcardEffectEnd]不能为空"); + } + // 其他的校验放到业务代码中处理 + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + // 变更结算类型 + Assert.notNull(reqModel.getSettlementType(), "结算方式[settlementType]不能为空"); + if (!reqModel.getSettlementType().equals(CS.SETTLEMENT_TYPE.D1) + && !reqModel.getSettlementType().equals(CS.SETTLEMENT_TYPE.D0) + && !reqModel.getSettlementType().equals(CS.SETTLEMENT_TYPE.T1)) { + throw new BizException("结算方式[settlementType]必须为【D0】、【D1】、【T1】"); + } + break; + default: + throw new BizException("未知的变更类型"); + } + + // check 只做存储,具体操作交由商户端进行 + MchModifyApplyment modifyApplyment = new MchModifyApplyment(); + + JeeUserDetails currentUser = getCurrentUser(); + modifyApplyment.setCreatedUid(currentUser.getSysUserId()); + modifyApplyment.setCreatedBy(currentUser.getUsername()); + modifyApplyment.setModifyApplyType(reqModel.getModifyApplyType()); + modifyApplyment.setApplyDetailInfo(JSON.toJSONString(reqModel)); + modifyApplyment.setModifyApplyId(SeqKit.genMchNotifyApplyNo()); + modifyApplyment.setApplyId(reqModel.getMchApplyId()); + modifyApplyment.setApplyPageType(CS.SYS_ROLE_TYPE.AGENT + "_" + getCurrentUser().getLoginType()); + + modifyApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_AFFIRM); + modifyApplyment.setChannelMchNo(mchApplyment.getChannelMchNo()); + modifyApplyment.setMchNo(mchApplyment.getMchNo()); + modifyApplyment.setOtherOperationType(operationType); + if ("1".equals(operationType)){ + modifyApplyment.setRemark("本地系统变更"); + } + modifyApplymentService.save(modifyApplyment); + + return ApiRes.ok(); + } + + /** + * 进件数据变更中的数据回显 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_LIST')") + @GetMapping("/modifyApplyment") + public ApiRes getModifyApplyment() { + // 变更类型,1: 本地变更; 2: 变更并同步到上游通道 + MchModifyApplymentModel reqModel = getObject(MchModifyApplymentModel.class); + String modifyApplyId = reqModel.getModifyApplyId(); + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + if (StringUtils.isNotEmpty(modifyApplyId)) { + qWrapper.eq(MchModifyApplymentEntity::getModifyApplyId, modifyApplyId); + } else { + Assert.notNull(reqModel.getMchApplyId(), "缺少商户编号[mchApplyId]"); + Assert.notNull(reqModel.getModifyApplyType(), "缺少商户编号[modifyApplyType]"); + qWrapper.eq(MchModifyApplymentEntity::getModifyApplyType, reqModel.getModifyApplyType()); + qWrapper.eq(MchModifyApplymentEntity::getApplyId, reqModel.getMchApplyId()); + qWrapper.eq(MchModifyApplymentEntity::getState, com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING); + } + MchModifyApplymentEntity existData = modifyApplymentService.getOne(qWrapper); + return ApiRes.ok(existData); + } + + @GetMapping("/getModifyApplyments") + public ApiRes getModifyApplyments() { + MchModifyApplymentEntity searchRecord = getObject(MchModifyApplymentEntity.class); + // 扩展员仅查询自己的数据 + if (getCurrentUser().isEpUser()) { + searchRecord.setEpUserId(getCurrentUser().getSysUser().getSysUserId()); + } + // 时间搜索 + Date[] searchDateRange = searchRecord.buildQueryDateRange(); + if (searchDateRange[0] != null) { + searchRecord.setFirstDate(searchDateRange[0]); + } + if (searchDateRange[1] != null) { + searchRecord.setLastDate(searchDateRange[1]); + } + Page page = getIPage(false); + Page result = mchApplymentService.getModifyApplyments(page, searchRecord); + //整理json数据 + result.getRecords().forEach(item -> { + if (!item.getApplyDetailInfo().isEmpty()) { + try { + MchModifyApplymentModel mchModifyApplymentModel = JSONObject.parseObject(item.getApplyDetailInfo(), new TypeReference() { + }.getType()); + item.setModifyModel(mchModifyApplymentModel); + } catch (Exception e) { + throw new BizException("解析json变更数据出错!"); + } + + } + }); + + return ApiRes.page(result); + } + /** + * 获取进件成功的通道 + * @return + */ + @GetMapping("/getSucceedIfName") + public ApiRes getSucceedIfName() { + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + List applymentList = mchApplymentService.list(MchApplyment.gw().select(MchApplyment::getIfCode, MchApplyment::getIfName) + .eq(MchApplyment::getState, MchApplyment.STATE_SUCCESS) + .in(MchApplyment::getAgentNo,subAgentNoList) + .groupBy(MchApplyment::getIfCode)); + return ApiRes.ok(applymentList); + } + + /** + * 获取进件成功的渠道 + * @return + */ + @GetMapping("/getSucceedIsvName") + public ApiRes getSucceedIsvName() { + MchApplyment mchApplyment = getObject(MchApplyment.class); + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + mchApplyment.setSubAgentNoList(subAgentNoList); + } + List succeedIsvName = mchApplymentService.getSucceedIsvName(mchApplyment); + return ApiRes.ok(succeedIsvName); + } +} + + + diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/YspayMchApplymentController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/YspayMchApplymentController.java new file mode 100644 index 0000000..d335f83 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/applyment/YspayMchApplymentController.java @@ -0,0 +1,282 @@ +package com.jeequan.jeepay.agent.ctrl.applyment; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.components.mq.model.MchAuditThirdNotifyMQ; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IYsApplymentApiService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchAppEntity; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchAppService; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/api/mchApplyments") +public class YspayMchApplymentController extends CommonCtrl { + + @Autowired private MchApplymentService mchApplymentService; + @Autowired private MchModifyApplymentService mchModifyApplymentService; + @Autowired private MchAppService mchAppService; + @Autowired private MchInfoConverter mchInfoConverter; + @Autowired private IMQSender mqSender; + + /** 银盛 上传图片 **/ + @PostMapping("/yspayUpload/{recordId}") + public ApiRes yspayUpload(@PathVariable("recordId") String recordId) { + JSONObject paramJSON = getReqParamJSON(); + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY && + dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class); + String respJSONStr = ""; + try { + // 更新参数 + dbRecord.setApplyDetailInfo(paramJSON.toJSONString()); + + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment mchApplymentImg = ysApplymentApiService.uploadImg(mchInfoConverter.toModel(dbRecord)); + + respJSONStr = mchApplymentImg.getChannelVar1(); + + MchApplyment updateRecord = new MchApplyment(); + updateRecord.setApplyDetailInfo(dbRecord.getApplyDetailInfo()); + BeanUtils.copyProperties(mchApplymentImg, updateRecord); + + // 更新数据 + updateRecord.setApplyId(recordId); + mchApplymentService.updateById(updateRecord); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(respJSONStr); + } + + /** 银盛 资料确认 **/ + @PostMapping("/yspayConfirm/{recordId}") + public ApiRes yspayConfirm(@PathVariable("recordId") String recordId) { + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_WAIT_VERIFY && + dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN && dbRecord.getState() != MchApplyment.STATE_FINISH_SIGN)) { + throw new BizException("当前申请单状态错误,无法继续。"); + } + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class); + String respJSONStr = ""; + try { + + // 提交审核 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.attachConfirm(mchInfoConverter.toModel(dbRecord)); + + respJSONStr = applymentResult.getApplyErrorInfo(); + + MchApplyment updateRecordAudit = new MchApplyment(); + BeanUtils.copyProperties(applymentResult, updateRecordAudit); + + // 更新数据 + updateRecordAudit.setApplyId(recordId); + mchApplymentService.updateById(updateRecordAudit); + + } catch (BizException e) { + logger.info("请求异常", e); + throw e; + } + + return ApiRes.ok(respJSONStr); + } + + /** 银盛 发起合同签约 **/ + @PostMapping("/ysSignApply/{recordId}") + public ApiRes ysSignApply(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class); + + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signApply(getReqParamJSON(), mchInfoConverter.toModel(dbRecord)); + + // 更新商户费率配置 + MchApplyment updateRecordAudit = new MchApplyment(); + BeanUtils.copyProperties(applymentResult, updateRecordAudit); + + // 更新数据 + updateRecordAudit.setApplyId(recordId); + mchApplymentService.updateById(updateRecordAudit); + + return ApiRes.ok(applymentResult.getChannelVar2()); + } + + /** 银盛 查询合同签约状态 **/ + @PostMapping("/ysSignQuery/{recordId}") + public ApiRes ysSignQuery(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + // 获取当前进件签约信息,未发起签约时为空 + if (StringUtils.isBlank(dbRecord.getChannelVar2())) { + return ApiRes.ok(); + } + + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(IYsApplymentApiService.class); + + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signQuery(mchInfoConverter.toModel(dbRecord)); + + // 更新商户费率配置 + MchApplyment updateRecordAudit = mchInfoConverter.toDbEntity(applymentResult); + + // 更新数据 + updateRecordAudit.setApplyId(recordId); + mchApplymentService.updateById(updateRecordAudit); + + if (updateRecordAudit.getState() == MchApplyment.STATE_SUCCESS) { + mchApplymentService.onApplymentSuccess(updateRecordAudit.getApplyId()); + mqSender.send(MchAuditThirdNotifyMQ.build(recordId, MchAuditThirdNotifyMQ.TYPE_AUDIT)); + } + + return ApiRes.ok(applymentResult.getChannelVar2()); + } + + /** 银盛 签约重发 **/ + @PostMapping("/ysSignSendAgain/{recordId}") + public ApiRes ysSignSendAgain(@PathVariable("recordId") String recordId) { + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + + if (dbRecord == null) { + MchModifyApplymentEntity modifyApplyment = mchModifyApplymentService.getById(recordId); + + if (modifyApplyment == null || modifyApplyment.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(CS.IF_CODE.YSPAY + "ApplymentApiService", IYsApplymentApiService.class); + + // 调起接口 + MchModifyApplyment applymentResult = ysApplymentApiService.signSendAgain(getReqParamJSON(), mchInfoConverter.toModel(modifyApplyment)); + + // 更新数据 + if (!StrUtil.isEmpty(applymentResult.getChannelVar1())) { + MchModifyApplymentEntity updateRecordAudit = new MchModifyApplymentEntity(); + updateRecordAudit.setApplyId(recordId); + updateRecordAudit.setChannelVar1(applymentResult.getChannelVar1()); + mchModifyApplymentService.updateById(updateRecordAudit); + } + + return ApiRes.ok(applymentResult.getChannelVar1()); + } else { + if (dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(CS.IF_CODE.YSPAY + "ApplymentApiService", IYsApplymentApiService.class); + + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.signSendAgain(getReqParamJSON(), mchInfoConverter.toModel(dbRecord)); + + // 更新数据 + if (!StrUtil.isEmpty(applymentResult.getChannelVar2())) { + MchApplyment updateRecordAudit = new MchApplyment(); + updateRecordAudit.setApplyId(recordId); + updateRecordAudit.setChannelVar2(applymentResult.getChannelVar2()); + mchApplymentService.updateById(updateRecordAudit); + } + + return ApiRes.ok(applymentResult.getChannelVar2()); + } + } + + /** 银盛费率配置 **/ + @PostMapping("/ysPayRateConfig/{recordId}") + public ApiRes ysPayRateConfig(@PathVariable("recordId") String recordId) { + + JSONObject reqParamJSON = getReqParamJSON(); + + MchApplyment dbRecord = mchApplymentService.getById(recordId); + if (dbRecord == null || (dbRecord.getState() != MchApplyment.STATE_AUDITING && dbRecord.getState() != MchApplyment.STATE_REJECT_WAIT_MODIFY + && dbRecord.getState() != MchApplyment.STATE_WAIT_SIGN)) { + throw new BizException("请刷新当前申请单状态,该申请单当前状态无法执行该操作。"); + } + + IYsApplymentApiService ysApplymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(dbRecord.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class); + + // 调起接口 + com.jeequan.jeepay.core.entity.MchApplyment applymentResult = ysApplymentApiService.payRateConfig(reqParamJSON, mchInfoConverter.toModel(dbRecord)); + + // 更新商户费率配置 + MchApplyment updateRecordAudit = new MchApplyment(); + // 配置成功更新费率 + if (applymentResult.getState() != null && applymentResult.getState() == MchApplyment.STATE_SUCCESS) { + BeanUtils.copyProperties(applymentResult, updateRecordAudit); + } else { + applymentResult.setApplyDetailInfo(null); + applymentResult.setState(MchApplyment.STATE_AUDITING); + BeanUtils.copyProperties(applymentResult, updateRecordAudit); + } + + // 更新数据 + updateRecordAudit.setApplyId(recordId); + mchApplymentService.updateById(updateRecordAudit); + + return ApiRes.ok(applymentResult.getChannelVar1()); + + } + + /** 银盛 配置相关信息 **/ + @PostMapping("/yspayInterfaceConfig/{applyId}/{mchAppId}") + public ApiRes yspayInterfaceConfig(@PathVariable("applyId") String applyId, @PathVariable("mchAppId") String mchAppId) { + + String configType = getValStringRequired("configType"); // PAY_BASE_URL, BIND_APP_ID, SUBSCRIBE_APP_ID, QUERY + String configVal = getValStringRequired("configVal"); + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + MchAppEntity mchAppEntity = mchAppService.getById(mchAppId); + + IYsApplymentApiService applymentApiService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(tbMchApplyment.getIfCode()) + "ApplymentApiService", IYsApplymentApiService.class); + + if ("PAY_BASE_URL".equals(configType)) { + + return ApiRes.ok(applymentApiService.configPayBaseUrl(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment))); + + } else if ("BIND_APP_ID".equals(configType)) { + + return ApiRes.ok(applymentApiService.configBindAppId(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment))); + + } else if ("SUBSCRIBE_APP_ID".equals(configType)) { + + return ApiRes.ok(applymentApiService.configSubscribeAppId(configVal, mchAppEntity.getAppId(), mchInfoConverter.toModel(tbMchApplyment))); + + } + + return ApiRes.customFail("没有[" + configType + "]配置"); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfApiController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfApiController.java new file mode 100644 index 0000000..fac5272 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfApiController.java @@ -0,0 +1,395 @@ +package com.jeequan.jeepay.agent.ctrl.aqf; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.response.AlipayFundAccountbookQueryResponse; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.service.impl.TransferSubjectService; +import com.jeequan.jeepay.service.impl.TransferWalletService; +import com.jeequan.jeepay.thirdparty.channel.alipay.AliAqfV2Service; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +@RestController +@RequestMapping("/api/aqfApi") +public class AqfApiController extends CommonCtrl { + + @Autowired + private AliAqfV2Service aliAqfV2Service; + + @Autowired + private SysConfigService sysConfigService; + + @Autowired + private TransferSubjectService transferSubjectService; + @Autowired + private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired + private TransferWalletService transferWalletService; + + /** + * 签约 + * + * @return + */ + @RequestMapping(value = "/signUrl", method = RequestMethod.GET) + public ApiRes signUrl() { + String subId = getValStringRequired("subId"); + String resutUrl = aliAqfV2Service.userAgreementPageSign(subId); + return ApiRes.ok(resutUrl); + } + + + /** + * 支付宝个人代扣协议查询接口 + * + * @return + */ + @RequestMapping(value = "/agreementQuery" , method = RequestMethod.GET) + public ApiRes agreementQuery(){ + String subId = getValStringRequired("subId"); + JSONObject alipayUserAgreementQueryResponse = aliAqfV2Service.userAgreementQuery(subId); + return ApiRes.ok(alipayUserAgreementQueryResponse); + } + + /** + * 解约 + * + * @return + */ + @RequestMapping(value = "/userAgreementUnsign" , method = RequestMethod.GET) + public ApiRes userAgreementUnsign(){ + String subId = getValStringRequired("subId"); + JSONObject alipayUserAgreementUnsignResponse = aliAqfV2Service.userAgreementUnsign(subId); + return ApiRes.ok(alipayUserAgreementUnsignResponse); + } + + /** + * 记账本查询 + * + * @return + */ + @RequestMapping(value = "/alipayFundAccountbookQuery", method = RequestMethod.GET) + public ApiRes alipayFundAccountbookQuery() { + String subId = getValStringRequired("subId"); + String walletApplyId = getValString("walletApplyId"); + // 设计上,一个签约主体可以创建多个记账本,实际使用的时候,尽量保持一个签约主体只有一个账本 + AlipayFundAccountbookQueryResponse alipayFundAccountbookQueryResponse = aliAqfV2Service.fundAccountbookQuery(walletApplyId); + return ApiRes.ok(JSON.parseObject(alipayFundAccountbookQueryResponse.getBody()).getJSONObject("alipay_fund_accountbook_query_response")); + } + + /** + * 资金专款拨入(商户自身给记账本充值) + * + * @return + */ + @RequestMapping(value = "/transPage" , method = RequestMethod.GET) + public ApiRes transPage(){ + String subId = getValStringRequired("subId"); + String transAmount = getValStringRequired("transAmount"); + String transferDesc = getValString("transferDesc"); + String transedUrl = aliAqfV2Service.transPage(subId, transAmount,transferDesc); + return ApiRes.ok(transedUrl); + } + + /** + * 单笔生成待发待结算信息 + * + * @return + */ + @RequestMapping(value = "/settlementData", method = RequestMethod.POST) + public ApiRes settlementDate() { + String currentAgentNo = getCurrentAgentNo(); + String transferSubjectIdFq = getValStringRequired("transferSubjectIdFq"); + String vc = Base64.decodeStr(getValStringRequired("vc")); + String vt = Base64.decodeStr(getValStringRequired("vt")); + String sipw = Base64.decodeStr(getValStringRequired("sipw")); + + // 验证码校验 + String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vt)); + if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vc)){ + throw new BizException("验证码有误!"); + } + + TransferSubjectEntity transferSubject = transferSubjectService.getById(transferSubjectIdFq); + if (!transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.AGENT) + || !currentAgentNo.equals(transferSubject.getAgentNo())) { + throw new BizException("非法操作"); + } + + AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo()); + if (!sipw.equals(agentInfo.getSipw())) { + throw new BizException("支付密码校验失败"); + } + + SettlementDataModel object = getObject(SettlementDataModel.class); + + String date = aliAqfV2Service.settlementData(object.getTransferSubjectIdFq(), object.getTransferOrders()); + return ApiRes.ok(date); + } + + /** + * 批量生成待结算数据,先入库再发起结算 + */ + @PostMapping("/batchSettlementData") + public ApiRes uploadExcel() { + + String currentAgentNo = getCurrentAgentNo(); + + String transferSubjectIdFq = getValStringRequired("transferSubjectIdFq"); + String excelFileName = getValStringRequired("excelFileName"); + File excelFile = channelCertConfigKitBean.getCertFile(excelFileName); + + SettlementDataModel params = getObject(SettlementDataModel.class); + + String vc = Base64.decodeStr(getValStringRequired("vc")); + String vt = Base64.decodeStr(getValStringRequired("vt")); + String sipw = Base64.decodeStr(getValStringRequired("sipw")); + + // 验证码校验 + String cacheCode = RedisUtil.getString(CS.getCacheKeyImgCode(vt)); + if(StringUtils.isEmpty(cacheCode) || !cacheCode.equalsIgnoreCase(vc)){ + throw new BizException("验证码有误!"); + } + + TransferSubjectEntity transferSubject = transferSubjectService.getById(transferSubjectIdFq); + if (!transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.AGENT) + || !currentAgentNo.equals(transferSubject.getAgentNo())) { + throw new BizException("非法操作"); + } + + AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo()); + if (!sipw.equals(agentInfo.getSipw())) { + throw new BizException("支付密码校验失败"); + } + + List dataList = new ArrayList<>(); + List transferOrderList = new ArrayList<>(); + String batch = "BATCH" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6); + try { + InputStream inputStream = Files.newInputStream(excelFile.toPath()); + EasyExcel.read(inputStream, SettleBatchExcel.class, new AnalysisEventListener() { + @Override + public void invoke(SettleBatchExcel settleBatchExcel, AnalysisContext analysisContext) { + dataList.add(settleBatchExcel); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + // 解析完成后的操作,可以在这里进行一些清理工作 + } + }).sheet().doRead(); + //把数据新增到收款信息中 + Assert.notEmpty(params.getTaskId(), "任务号不能为空"); + + TransferSubjectEntity sponsor = transferSubjectService.getById(params.getTransferSubjectIdFq()); + if (!getCurrentAgentNo().equalsIgnoreCase(sponsor.getAgentNo())) { + throw new BizException("参数非法"); + } + + if (!Objects.equals(sponsor.getState(), TransferSubject.STATE_ENABLE)) { + throw new BizException("付款账户当前状态不可用"); + } + + if (!Objects.equals(sponsor.getSignState(), (int) TransferSubject.SIGN_STATE_SUCCESS)) { + throw new BizException("付款账户暂未完成签约"); + } + + TransferWalletEntity transferWallet = transferWalletService.getByApplyId(sponsor.getTransApplyId(), null); + String extCardInfo = transferWallet.getExtCardInfo(); + + JSONObject extCardJSON = JSONObject.parseObject(extCardInfo); + + Assert.notNull(sponsor, "未获取到对应的转账发起方信息"); + + for (SettleBatchExcel settleBatchExcel : dataList) { + TransferSubjectEntity receiver = transferSubjectService.getReceiver(sponsor.getIsvNo(), + CS.IF_CODE.ALIAQF, CS.SYS_ROLE_TYPE.AGENT, getCurrentAgentNo(), settleBatchExcel.getAccountNo(), + settleBatchExcel.getEntryType(), settleBatchExcel.getAccountType()); + if (receiver == null) { + // 先存储转账接受账户信息 + receiver = new TransferSubjectEntity(); + receiver.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6)); + receiver.setAccount(settleBatchExcel.getAccountNo()); + receiver.setState(TransferSubject.STATE_ENABLE); + receiver.setSubjectType(TransferSubject.SUBJECT_TYPE_RECEIVER); + receiver.setIsvNo(sponsor.getIsvNo()); + receiver.setInfoType(sponsor.getInfoType()); + receiver.setMchNo(sponsor.getMchNo()); + receiver.setAgentNo(sponsor.getAgentNo()); + receiver.setAgentName(sponsor.getAgentName()); + receiver.setTopAgentNo(sponsor.getTopAgentNo()); + receiver.setTransIfCode(sponsor.getTransIfCode()); + receiver.setSignState(sponsor.getSignState()); + receiver.setAccountName(settleBatchExcel.getAccountName()); + receiver.setAccountType(settleBatchExcel.getAccountType()); + receiver.setEntryType(settleBatchExcel.getEntryType()); + transferSubjectService.save(receiver); + + if (TransferBasicInfo.ENTRY_TYPE_BANK.equalsIgnoreCase(settleBatchExcel.getEntryType())) { + // 保存银联支行信息 + JSONObject bankCardBranchInfo = new JSONObject(); + if (settleBatchExcel.getInstCity() != null) { + bankCardBranchInfo.put("instName", settleBatchExcel.getInstName()); + bankCardBranchInfo.put("instProvince", settleBatchExcel.getInstProvince()); + bankCardBranchInfo.put("instCity", settleBatchExcel.getInstCity()); + bankCardBranchInfo.put("instBranchName", settleBatchExcel.getInstBranchName()); + } + + receiver.setAccountMessage(bankCardBranchInfo.toJSONString()); + } + } + + // 保存一些订单信息 + TransferOrder transferOrder = new TransferOrder(); + transferOrder.setMchNo(sponsor.getMchNo()); + transferOrder.setIsvNo(sponsor.getIsvNo()); + transferOrder.setAgentNo(sponsor.getAgentNo()); + transferOrder.setTransferSubjectIdFq(params.getTransferSubjectIdFq()); + transferOrder.setTransferSubjectIdJs(receiver.getId()); + transferOrder.setIfCode(receiver.getTransIfCode()); + transferOrder.setWalletId(transferWallet.getId()); + transferOrder.setEntryType(settleBatchExcel.getEntryType()); + transferOrder.setAccountType(settleBatchExcel.getAccountType()); + transferOrder.setAccountName(settleBatchExcel.getAccountName()); + transferOrder.setAccountNo(settleBatchExcel.getAccountNo()); + transferOrder.setOriginAccountNo(sponsor.getAccount()); + transferOrder.setOriginAccountName(sponsor.getAccountName()); + transferOrder.setBatchId(batch); + transferOrderList.add(transferOrder); + } + //新增或更新完毕后发起结算 + + aliAqfV2Service.settlementData(params.getTransferSubjectIdFq(), transferOrderList); + + } catch (IOException e) { + logger.info("批量导入安全发代发数据解析失败!"); + // 处理异常 + } + // 对 dataList 进行后续操作,如存储到数据库等 + return ApiRes.ok(); + } + +// /** +// * 代发到户 --不直接调用 +// * @return +// */ +// @RequestMapping(value = "/transUniTransfer" , method = RequestMethod.GET) +// public ApiRes transUniTransfer(){ +// String ersubId = getValStringRequired("ersubId"); +// String eesubId = getValStringRequired("eesubId"); +// String transAmount = getValStringRequired("transAmount"); +// String taskId = getValStringRequired("taskId"); +// String transferDesc = getValString("transferDesc"); +// AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = aliAqfV2Service.transUniTransfer(ersubId, eesubId, getDefaultIsvConfig(), transAmount,taskId,null,transferDesc); +// return ApiRes.ok(alipayFundTransUniTransferResponse); +// } + +// /** +// * 代发到卡 --不直接调用 +// * @return +// */ +// @RequestMapping(value = "/transUniTransferCard" , method = RequestMethod.GET) +// public ApiRes transUniTransferCard(){ +// String ersubId = getValStringRequired("ersubId"); +// String eesubId = getValStringRequired("eesubId"); +// String transAmount = getValStringRequired("transAmount"); +// String taskId = getValStringRequired("taskId"); +// String transferDesc = getValString("transferDesc"); +// AlipayFundTransUniTransferResponse alipayFundTransUniTransferResponse = aliAqfV2Service.transUniTransferCard(ersubId, eesubId, getDefaultIsvConfig(), transAmount, taskId,null,transferDesc); +// return ApiRes.ok(alipayFundTransUniTransferResponse); +// } + + /** + * 账单查询 + * + * @return + */ + @RequestMapping(value = "/bizfundagentQuery", method = RequestMethod.GET) + public ApiRes bizfundagentQuery() { + String ersubId = getValStringRequired("ersubId"); + String startTime = getValStringRequired("startTime"); + String endTime = getValStringRequired("endTime"); + String pageNo = getValStringRequired("pageNo"); + String pageSize = getValStringRequired("pageSize"); + JSONObject alipayDataBillBizfundagentQueryResponse = aliAqfV2Service.bizfundagentQuery(ersubId, startTime, endTime, pageNo, pageSize); + return ApiRes.ok(alipayDataBillBizfundagentQueryResponse); + } + + /** + * 电子回单申请 + * + * @return + */ + @RequestMapping(value = "/applicationForm", method = RequestMethod.GET) + public ApiRes applicationForm() { + + String ersubId = getValStringRequired("ersubId"); + String transferId = getValStringRequired("transferId"); + JSONObject alipayDataBillEreceiptagentApplyResponse = aliAqfV2Service.applicationForm(ersubId, transferId); + return ApiRes.ok(alipayDataBillEreceiptagentApplyResponse); + } + + /** + * 电子回单下载地址获取 + * + * @return + */ + @RequestMapping(value = "/applicationFormDownload", method = RequestMethod.GET) + public ApiRes applicationFormDownload() { + String ersubId = getValStringRequired("ersubId"); + String transferId = getValStringRequired("transferId"); + JSONObject alipayDataBillAccountbookereceiptQueryResponse = aliAqfV2Service.applicationFormDownload(ersubId, transferId); + return ApiRes.ok(alipayDataBillAccountbookereceiptQueryResponse); + } + + public String getDefaultIsvConfig() { + SysConfig serviceOne = sysConfigService.getOne(SysConfig.gw().eq(SysConfig::getGroupKey, "defaultConfig") + .eq(SysConfig::getConfigKey, "defaultIsvNo")); + if (serviceOne != null) { + return serviceOne.getConfigVal(); + } + return null; + } + /** + * 根据付款人信息id获取详情 + */ + public TransferSubjectEntity getSubjectOne(String subId){ + TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(subId); + if (transferSubjectEntity != null){ + return transferSubjectEntity; + }else { + throw new BizException("未查询到当前付款人信息!"); + } + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfController.java new file mode 100644 index 0000000..451749c --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/AqfController.java @@ -0,0 +1,214 @@ +package com.jeequan.jeepay.agent.ctrl.aqf; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.service.impl.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 转账对象信息 + */ +@RestController +@RequestMapping("/api/aqf") +public class AqfController extends CommonCtrl { + + @Autowired + private TransferSubjectService transferSubjectService; + + @Autowired + private TransferInterfaceConfigService transferInterfaceConfigService; + + @Autowired + private IsvInfoService isvInfoService; + + @Autowired + private AgentInfoService agentInfoService; + + @Autowired + private MchInfoService mchInfoService; + + /** + * 新增付款方账户信息 + * + * @return + */ + @RequestMapping(value = "/add", method = RequestMethod.POST) + public ApiRes addTransferSubject() { + TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class); + // 当前登录用户信息 + transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6)); + SysUser sysUser = getCurrentUser().getSysUser(); + transferSubject.setSubjectType("FQ"); + transferSubject.setTransApplyId(UUID.randomUUID().toString().replace("-", "").substring(0, 32)); + //当前服务商 + transferSubject.setAgentNo(getCurrentAgentNo()); + //获取渠道信息 + AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo()); + transferSubject.setIsvNo(agentInfo.getIsvNo()); + + transferSubject.setCreatedUid(sysUser.getSysUserId()); + boolean save = transferSubjectService.save(transferSubject); + if (save) { + return ApiRes.ok(); + } else { + return ApiRes.customFail("新增失败!"); + } + } + + /** + * 查询 + */ + @GetMapping("/getPageList") + public ApiRes pageTransferSubject() { + TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class); + // 时间搜索 + Date[] searchDateRange = transferSubject.buildQueryDateRange(); + transferSubject.setFirstDate(searchDateRange[0]); + transferSubject.setLastDate(searchDateRange[1]); + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + transferSubject.setSubAgentNoList(subAgentNoList); + } + IPage pageList = transferSubjectService.getPageList(getIPage(), transferSubject); + return ApiRes.page(pageList); + } + + /** + * 查询详情 + */ + @GetMapping(value = "/{id}") + public ApiRes getByIdTransferSubject(@PathVariable("id") Integer id) { + TransferSubjectEntity byId = transferSubjectService.getById(id); + return ApiRes.ok(byId); + } + + /** + * 修改 + */ + @PutMapping(value = "/{id}") + public ApiRes updateTransferSubject(@PathVariable("id") String id) { + TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class); + + transferSubject.setId(id); + //当前服务商 + transferSubject.setAgentNo(getCurrentAgentNo()); + //获取渠道信息 + AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo()); + transferSubject.setIsvNo(agentInfo.getIsvNo()); + boolean resut = transferSubjectService.updateById(transferSubject); + if (resut) { + return ApiRes.ok(); + } else { + return ApiRes.customFail("修改失败!"); + } + } + + /** + * 删除 + */ + @DeleteMapping("/{id}") + public ApiRes deleteTransferSubject(@PathVariable("id") Integer id) { + boolean resut = transferSubjectService.removeById(id); + if (resut) { + return ApiRes.ok(); + } else { + return ApiRes.customFail("删除失败!"); + } + } + + /** + * 新增收款方账户信息 + */ + @PostMapping("/addJs") + public ApiRes addJsTransferSubject() { + TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class); + // 当前登录用户信息 + transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6)); + SysUser sysUser = getCurrentUser().getSysUser(); + transferSubject.setSubjectType("JS"); + transferSubject.setCreatedUid(sysUser.getSysUserId()); + //当前服务商 + transferSubject.setAgentNo(getCurrentAgentNo()); + //获取渠道信息 + AgentInfo agentInfo = agentInfoService.getById(transferSubject.getAgentNo()); + transferSubject.setIsvNo(agentInfo.getIsvNo()); + boolean save = transferSubjectService.save(transferSubject); + if (save) { + return ApiRes.ok(); + } else { + return ApiRes.customFail("新增失败!"); + } + } + + @GetMapping("/getBatchData") + public ApiRes getBatchData() { + String transferSubjects = getValStringRequired("transferSubjects"); + List transferSubjectEntityList = new ArrayList<>(); + String[] transferSubjectSpli = transferSubjects.split(","); + for (String transferSubjectId : transferSubjectSpli) { + TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(transferSubjectId); + if (transferSubjectEntity != null) { + transferSubjectEntityList.add(transferSubjectEntity); + } + } + return ApiRes.ok(transferSubjectEntityList); + } + + @PostMapping("/state") + public ApiRes exam() { + JSONObject reqParamJSON = getReqParamJSON(); + Integer state = reqParamJSON.getInteger("state"); + String id = reqParamJSON.getString("id"); + String remark = reqParamJSON.getString("remark"); + + TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(id); + Assert.notNull(transferSubjectEntity, "付款账户信息不存在"); + + if (state == TransferSubject.STATE_DISABLE) { + transferSubjectEntity.setState(TransferSubject.STATE_DISABLE); + transferSubjectEntity.setRemark(remark); + transferSubjectService.updateById(transferSubjectEntity); + } else if (state == TransferSubject.STATE_ENABLE) { + transferSubjectEntity.setState(TransferSubject.STATE_ENABLE); + transferSubjectService.updateById(transferSubjectEntity); + } else if (state == TransferSubject.STATE_ENABLE_REVIEW) { + transferSubjectEntity.setState(TransferSubject.STATE_ENABLE_REVIEW); + transferSubjectService.updateById(transferSubjectEntity); + } + + return ApiRes.ok(); + } + + /** + * 统计收款账户总成交金额和总成交笔数 + */ + @GetMapping("/getSubStatistics") + public Map getSubStatistics(){ + TransferSubjectEntity subject = getObject(TransferSubjectEntity.class); + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + subject.setSubAgentNoList(subAgentNoList); + } + return transferSubjectService.getSubStatistics(subject); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TaskListController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TaskListController.java new file mode 100644 index 0000000..10de81e --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TaskListController.java @@ -0,0 +1,120 @@ +package com.jeequan.jeepay.agent.ctrl.aqf; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.TaskList; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.TaskListService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.List; + +/** + * 任务 + */ +@RestController +@RequestMapping("/api/taskList") +public class TaskListController extends CommonCtrl { + + @Autowired + private TaskListService taskListService; + + @Autowired + private MchInfoService mchInfoService; + + /** + * 新增任务 + * @return + */ + @RequestMapping(value = "/add" ,method = RequestMethod.POST) + public ApiRes addTaskList(){ + TaskList taskList = getObject(TaskList.class); + //当前服务商 + taskList.setAgentNo(getCurrentAgentNo()); + // 当前登录用户信息 + SysUser sysUser = getCurrentUser().getSysUser(); + taskList.setId(DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6)); + taskList.setCreatedBy(String.valueOf(sysUser.getSysUserId())); + boolean save = taskListService.save(taskList); + if (save){ + return ApiRes.ok(); + }else { + return ApiRes.customFail("新增失败!"); + } + } + /** + * 查询 + * @return + */ + @RequestMapping(value = "/getPageList" ,method = RequestMethod.GET) + public ApiRes getlistTaskList(){ + TaskList taskList = getObject(TaskList.class); + // 时间搜索 + Date[] searchDateRange = taskList.buildQueryDateRange(); + taskList.setFirstDate(searchDateRange[0]); + taskList.setLastDate(searchDateRange[1]); + taskList.setAgentNo(getCurrentAgentNo()); + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + taskList.setSubAgentNoList(subAgentNoList); + } + IPage pageList = taskListService.getPageList(getIPage(), taskList); + //Page page = taskListService.page(getIPage(), TaskList.gw(taskList).orderByDesc(TaskList::getCreatedAt)); + return ApiRes.page(pageList); + } + /** + * 查询详情 + * @return + */ + @RequestMapping(value = "/{id}" ,method = RequestMethod.GET) + public ApiRes getByIdTaskList(@PathVariable("id") Integer id){ + TaskList byId = taskListService.getById(id); + return ApiRes.ok(byId); + } + + /** + * 修改 + * @return + */ + @RequestMapping(value = "/{id}" ,method = RequestMethod.PUT) + public ApiRes updateTaskList(@PathVariable("id") String id){ + TaskList taskList = getObject(TaskList.class); + //当前服务商 + taskList.setAgentNo(getCurrentAgentNo()); + taskList.setId(id); + boolean resut = taskListService.updateById(taskList); + if (resut){ + return ApiRes.ok(); + }else { + return ApiRes.customFail("修改失败!"); + } + } + + /** + * 删除 + * @return + */ + @RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE) + public ApiRes deleteTaskList(@PathVariable("id") Integer id){ + boolean resut = taskListService.removeById(id); + if (resut){ + return ApiRes.ok(); + }else { + return ApiRes.customFail("删除失败!"); + } + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TransferSubjectController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TransferSubjectController.java new file mode 100644 index 0000000..621c63d --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/aqf/TransferSubjectController.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.agent.ctrl.aqf; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.converter.TransferConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.interfaces.paychannel.ITransferService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.service.ValidatorService; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.core.validate.Add; +import com.jeequan.jeepay.db.entity.SysConfig; +import com.jeequan.jeepay.db.entity.TransferInterfaceConfigEntity; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.db.entity.TransferWalletEntity; +import com.jeequan.jeepay.service.impl.TransferInterfaceConfigService; +import com.jeequan.jeepay.service.impl.TransferSubjectService; +import com.jeequan.jeepay.service.impl.TransferWalletService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.UUID; + +/** + * 代付对象 + * + * @author deng + * @since 2024/5/9 + */ +@Slf4j +@RestController +@RequestMapping("/api/transferSubject") +public class TransferSubjectController extends CommonCtrl { + + @Autowired + private TransferInterfaceConfigService transferInterfaceConfigService; + + @Autowired + private ValidatorService validate; + + @Autowired + private TransferSubjectService transferSubjectService; + + @Autowired + private TransferWalletService transferWalletService; + + @Autowired + private TransferConverter transferConverter; + + /** + * 新增转账发起方 + */ + @PostMapping("/sponsor") + public ApiRes sponsor() { + TransferSubjectEntity transferSubject = getObject(TransferSubjectEntity.class); + + validate.validate(transferSubject, Add.class); + + // 当前登录用户信息 + transferSubject.setId("SUB" + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6)); + SysUser sysUser = getCurrentUser().getSysUser(); + transferSubject.setSubjectType("FQ"); + transferSubject.setTransApplyId(UUID.randomUUID().toString().replace("-", "").substring(0, 32)); + + //如果不传递取默认值 + if (StringUtils.isEmpty(transferSubject.getIsvNo())) { + SysConfig serviceOne = sysConfigService.getOne(SysConfig.gw().eq(SysConfig::getGroupKey, "defaultConfig") + .eq(SysConfig::getConfigKey, "defaultIsvNo")); + if (serviceOne != null) { + transferSubject.setIsvNo(serviceOne.getConfigVal()); + } + } + if (StringUtils.isNotEmpty(transferSubject.getIsvNo())) { + //取对应参数信息 + //获取下发金额 + TransferInterfaceConfigEntity configEntity = transferInterfaceConfigService.getTransferConfig(transferSubject.getTransIfCode(), transferSubject.getIsvNo(), CS.SYS_ROLE_TYPE.ISV); + + if (configEntity != null && StringUtils.isNotEmpty(configEntity.getTransIfParams())) { + String zfbDayMax = JSONObject.parseObject(configEntity.getTransIfParams()).getString("zfbDayMax"); + String bankCardDayMax = JSONObject.parseObject(configEntity.getTransIfParams()).getString("bankCardDayMax"); + transferSubject.setZfbDayMax(Long.valueOf(zfbDayMax)); + transferSubject.setBankCardDayMax(Long.valueOf(bankCardDayMax)); + } + } + + transferSubject.setCreatedUid(sysUser.getSysUserId()); + boolean save = transferSubjectService.save(transferSubject); + if (save) { + return ApiRes.ok(); + } else { + return ApiRes.customFail("新增失败!"); + } + } + + @PostMapping("/refreshBalance") + public ApiRes refreshBalance() { + String transferSubjectId = getValStringRequired("transferSubjectId"); + TransferWalletEntity transferWallet = transferWalletService.getByApplyId(transferSubjectId, null); + + SpringBeansUtil.getBean(transferWallet.getTransIfCode() + "Transfer"); + + // 刷新记账本余额 + ITransferService transferService = SpringBeansUtil.getBean(transferWallet.getTransIfCode() + "TransferService", ITransferService.class); + + MutablePair balanceResult = transferService.queryBalanceAmount(transferConverter.toModel(transferWallet)); + // 查询更新余额 + transferWallet.setAccountBookBalance(balanceResult.right); + transferWalletService.updateById(transferWallet); + + return ApiRes.ok(transferWallet); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/article/SysArticleController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/article/SysArticleController.java new file mode 100644 index 0000000..90f1346 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/article/SysArticleController.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.agent.ctrl.article; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.SysArticle; +import com.jeequan.jeepay.service.impl.SysArticleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * 文章管理类 + * + * @author yurong + * @date 2022-07-08 14:15 + */ +@RestController +@RequestMapping("api/sysArticles") +public class SysArticleController extends CommonCtrl { + + @Autowired private SysArticleService sysArticleService; + + /** + * @author: yurong + * @date: 2022-07-08 14:15 + * @describe: 文章列表 articleType 1:公告 + */ + @PreAuthorize("hasAuthority('ENT_ARTICLE_NOTICEINFO')") + @RequestMapping(value = "",method = RequestMethod.GET) + public ApiRes articleList(){ + SysArticle sysArticle = getObject(SysArticle.class); + if (sysArticle.getArticleType() == null){ + return ApiRes.customFail("文章类型不明确"); + } + LambdaQueryWrapper wrapper = SysArticle.gw(); + wrapper.select(SysArticle::getArticleId,SysArticle::getTitle,SysArticle::getSubtitle,SysArticle::getPublisher,SysArticle::getCreatedAt) + .eq(SysArticle::getArticleType,sysArticle.getArticleType()) + .apply("FIND_IN_SET('"+ CS.SYS_ROLE_TYPE.AGENT+"',"+SysArticle.ARTICLE_RANGE+")") + .orderByDesc(SysArticle::getPublishTime); + IPage iPage = sysArticleService.page(getIPage(), wrapper); + return ApiRes.page(iPage); + } + + /** + * @author: yurong + * @date: 2022-07-08 14:15 + * @describe: 文章详情 articleType 1:公告 + */ + @PreAuthorize("hasAuthority('ENT_ARTICLE_NOTICEINFO')") + @RequestMapping(value = "/{articleId}",method = RequestMethod.GET) + public ApiRes detail(@PathVariable("articleId") Long articleId){ + SysArticle sysArticle = sysArticleService.getById(articleId); + if (sysArticle == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + return ApiRes.ok(sysArticle); + } +} + diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/isv/IsvInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/isv/IsvInfoController.java new file mode 100644 index 0000000..61e46af --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/isv/IsvInfoController.java @@ -0,0 +1,163 @@ +package com.jeequan.jeepay.agent.ctrl.isv; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.IsvInfo; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.IsvInfoEntity; +import com.jeequan.jeepay.db.entity.MchConfig; +import com.jeequan.jeepay.service.impl.IsvInfoService; +import com.jeequan.jeepay.service.impl.PayInterfaceConfigService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 服务商管理类 + * + * @author pangxiaoyu + * @date 2021-06-07 07:15 + */ +@RestController +@RequestMapping("/api/isvInfo") +public class IsvInfoController extends CommonCtrl { + + @Autowired + private IsvInfoService isvInfoService; + + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:12 + * @describe: 查询服务商信息列表 + */ + @PreAuthorize("hasAuthority('ENT_ISV_LIST')") + @RequestMapping(value = "", method = RequestMethod.GET) + public ApiRes list() { + IsvInfoEntity isvInfoEntity = getObject(IsvInfoEntity.class); + LambdaQueryWrapper wrapper = IsvInfoEntity.gw(); + if (StringUtils.isNotEmpty(isvInfoEntity.getIsvNo())) { + wrapper.eq(IsvInfoEntity::getIsvNo, isvInfoEntity.getIsvNo()); + } + if (StringUtils.isNotEmpty(isvInfoEntity.getIsvName())) { + wrapper.eq(IsvInfoEntity::getIsvName, isvInfoEntity.getIsvName()); + } + if (isvInfoEntity.getState() != null) { + wrapper.eq(IsvInfoEntity::getState, isvInfoEntity.getState()); + } + wrapper.orderByDesc(IsvInfoEntity::getCreatedAt); + IPage pages = isvInfoService.page(getIPage(true), wrapper); + + return ApiRes.page(pages); + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:13 + * @describe: 查看服务商信息 + */ + @PreAuthorize("hasAnyAuthority('ENT_ISV_INFO_VIEW', 'ENT_ISV_INFO_EDIT')") + @RequestMapping(value = "/{isvNo}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("isvNo") String isvNo) { + IsvInfoEntity isvInfoEntity = isvInfoService.getById(isvNo); + if (isvInfoEntity == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + return ApiRes.ok(isvInfoEntity); + } + + @GetMapping("/isvInfoList") + public ApiRes getIsvInfoList() { + String ifCode = getValStringRequired("ifCode"); + String infoType = getValStringRequired("infoType"); + String infoId = getValStringRequired("infoId"); + String range = getValString("range"); + Integer state = getValInteger("state"); + String isvName = getValString("isvName"); + + if ("CURRENTAGENT".equals(infoId)) { + infoId = getCurrentAgentNo(); + } + + List isvAndPayConfig = isvInfoService.getIsvAndPayConfig(infoType, isvName, infoId, ifCode, range, state); + + Page page = new Page<>(); + page.setRecords(isvAndPayConfig); + page.setSize(-1); + page.setPages(1); + + if (!CS.SYS_ROLE_TYPE.MCH.equals(infoType)) { + return ApiRes.ok(page); + } + + // 如果是查看商户数据,则查询他的默认渠道 + List> defIsv = mchInfoService.getDefIsv(infoId, ifCode); + if (!ObjectUtils.isEmpty(defIsv)) { + Map defIsvItem = defIsv.get(0); + + page.getRecords().forEach(r -> { + if (r.getIsvNo().equals(defIsvItem.get(MchConfig.getDefIsvKey(ifCode)))) { + r.addExt("defIsv", CS.YES); + } + }); + } + + return ApiRes.ok(page); + } + + @PostMapping("/autoBindIsvConn") + public ApiRes autoBindIsvConn() { + String isvNo = getValStringRequired("isvNo"); + String infoId = getValStringRequired("infoId"); + String roleType = getValStringRequired("roleType"); + Byte configStatus = getValByteRequired("configStatus"); + + isvInfoService.autoBindIsvConn(isvNo, infoId, roleType, configStatus); + + return ApiRes.ok(); + } + + @PostMapping("/isvConn") + public ApiRes isvConn() { + String isvNo = getValStringRequired("isvNo"); + String infoId = getValStringRequired("infoId"); + String infoType = getValStringRequired("infoType"); + + isvInfoService.saveIsvConn(isvNo, infoType, infoId, getCurrentUser().getSysUser()); + + return ApiRes.ok(); + } + + @GetMapping("/getSettType") + public ApiRes getSettType() { + String ifCode = getValStringRequired("ifCode"); + String infoId = getValStringRequired("infoId"); + JSONArray settType = isvInfoService.getSettType(ifCode, infoId); + return ApiRes.ok(settType); + } + + @PostMapping("/editStatus") + public ApiRes editStatus() { + String isvNo = getValStringRequired("isvNo"); + String ifCode = getValStringRequired("ifCode"); + String infoId = getValStringRequired("infoId"); + String infoType = getValStringRequired("infoType"); + Integer status = getValIntegerRequired("state"); + + isvInfoService.editConnStatus(isvNo, ifCode, infoId, infoType, status); + + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/ImgInfoOCRController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/ImgInfoOCRController.java new file mode 100644 index 0000000..61a63bc --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/ImgInfoOCRController.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.OCRImgParams; +import com.jeequan.jeepay.service.impl.ImgInfoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 图片信息OCR + * + * @author xiaoyu + * + * @date 2022/1/12 15:15 + */ +@RestController +@RequestMapping("/api/imgInfo") +public class ImgInfoOCRController extends CommonCtrl { + + @Autowired private ImgInfoService imgInfoService; + + /** 图片信息 **/ + @PreAuthorize("hasAuthority('ENT_MCH_IMG_OCR_DETAIL')") + @PostMapping("/detail") + public ApiRes detail() { + String imgUrl = getValStringRequired("imgUrl"); + String type = getValStringRequired("type"); + // 调用ocr接口 + OCRImgParams imgParams = imgInfoService.getImgInfo(imgUrl, type); + return ApiRes.ok(imgParams); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MainChartController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MainChartController.java new file mode 100644 index 0000000..896c82a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MainChartController.java @@ -0,0 +1,163 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBOEMConfig; +import com.jeequan.jeepay.core.service.ISysConfigService; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.db.entity.ToDoListModel; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.PayOrderService; +import com.jeequan.jeepay.service.impl.StatsTradeService; +import com.jeequan.jeepay.service.impl.SysUserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 主页数据类 + * + * @author pangxiaoyu + * + * @date 2021-04-27 15:50 + */ +@Slf4j +@RestController +@RequestMapping("/api/mainChart") +public class MainChartController extends CommonCtrl { + + @Autowired private PayOrderService payOrderService; + + @Autowired private SysUserService sysUserService; + + @Autowired private AgentInfoService agentInfoService; + @Autowired private ISysConfigService sysConfigService; + @Autowired private StatsTradeService statsTradeService; + + /** + * @author: xiaoyu + * @date: 2021/12/28 14:54 + * @describe: 今日/昨日交易统计 + */ + @PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_DAY_COUNT')") + @RequestMapping(value="/payDayCount", method = RequestMethod.GET) + public ApiRes payDayCount() { + JSONObject reqParamJSON = getReqParamJSON(); + + List agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + // Map agentNoMap = getAgentNo(reqParamJSON); + // JSONObject resJson = payOrderService.payDayCount(null, agentNoMap.get("agentNo"), agentNoMap.get("topAgentNo"), reqParamJSON); + JSONObject resJson = statsTradeService.payDayCount(null, agentSubList, reqParamJSON); + return ApiRes.ok(resJson); + } + + /** + * @author: xiaoyu + * @date: 2021/12/28 14:53 + * @describe: 趋势图数据 + */ + @PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_TREND_COUNT')") + @RequestMapping(value="/payTrendCount", method = RequestMethod.GET) + public ApiRes payTrendCount() { + JSONObject paramJSON = getReqParamJSON(); + int recentDay = paramJSON.getIntValue("recentDay"); + if (recentDay == 0){ + recentDay = 30; // 默认30天 + } + paramJSON.put("recentDay", recentDay); + List agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + + JSONObject resJson = payOrderService.payTrendCount(paramJSON, null, agentSubList); + return ApiRes.ok(resJson); + } + + /** + * @author: xiaoyu + * @date: 2021/12/28 14:54 + * @describe: 交易统计 + */ + @PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_COUNT')") + @RequestMapping(value="/payCount", method = RequestMethod.GET) + public ApiRes payCount() { + Map agentNoMap = getAgentNo(getReqParamJSON()); + List agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + // 获取传入参数 + JSONObject resJson = payOrderService.mainPagePayCount(null, agentSubList, getReqParamJSON()); + return ApiRes.ok(resJson); + } + + /** + * @author: xiaoyu + * @date: 2021/12/28 14:54 + * @describe: 支付方式统计 + */ + @PreAuthorize("hasAuthority('ENT_AGENT_MAIN_PAY_TYPE_COUNT')") + @RequestMapping(value="/payTypeCount", method = RequestMethod.GET) + public ApiRes payWayCount() { + Map agentNoMap = getAgentNo(getReqParamJSON()); + List agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + ArrayList arrayResult = payOrderService.mainPagePayTypeCount(null, agentSubList, getReqParamJSON()); + return ApiRes.ok(arrayResult); + } + + /** + * @author: xiaoyu + * @date: 2021/12/28 14:54 + * @describe: 服务商基本信息、用户基本信息 + */ + @PreAuthorize("hasAuthority('ENT_C_USERINFO')") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes userDetail() { + SysUserEntity sysUserEntity = sysUserService.getById(getCurrentUser().getSysUser().getSysUserId()); + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + Byte infoState = getCurrentUser().getInfoState(); + DBOEMConfig dboemConfig = sysConfigService.getOemConfig(); + + JSONObject json = (JSONObject) JSON.toJSON(agentInfo); + json.put("promiseFile", dboemConfig.getPromiseFile()); + json.put("loginUsername", sysUserEntity.getLoginUsername()); + json.put("realname", sysUserEntity.getRealname()); + json.put("infoState", infoState); + return ApiRes.ok(json); + } + + /** + * @author: xiaoyu + * @date: 2022/3/18 16:20 + * @describe: 与app共用接口返回服务商号 + */ + public Map getAgentNo(JSONObject paramJSON) { + HashMap AgentNoMap = new HashMap<>(); + String agentNo = null; + String topAgentNo = getCurrentAgentNo(); + if (StringUtils.isNotEmpty(paramJSON.getString("agentNo"))) { + agentNo = paramJSON.getString("agentNo"); + } + AgentNoMap.put("agentNo", agentNo); + AgentNoMap.put("topAgentNo", topAgentNo); + return AgentNoMap; + } + /** + * + * @describe (待办事项)汇总待审核或者待操作的事件数量 + * + * @return + */ + @RequestMapping(value = "/getWaitOperationNumber",method = RequestMethod.GET) + public ApiRes getWaitOperationNumber(){ + List waitOperationNumber = new ArrayList<>(); + return ApiRes.ok(waitOperationNumber); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchAppController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchAppController.java new file mode 100644 index 0000000..48627a4 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchAppController.java @@ -0,0 +1,186 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.db.entity.MchAppEntity; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.service.impl.MchAppService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 商户应用管理类 + * + * @author zhuxiao + * + * @date 2021-06-16 09:15 + */ +@RestController +@RequestMapping("/api/mchApps") +public class MchAppController extends CommonCtrl { + + @Autowired private MchAppService mchAppService; + @Autowired private MchInfoService mchInfoService; + @Autowired private SystemYmlConfig systemYmlConfig; + @Autowired private IMQSender mqSender; + + /** + * @Author: ZhuXiao + * @Description: 应用列表 + * @Date: 9:59 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APP_LIST')") + @GetMapping + public ApiRes list() { + MchAppEntity mchAppEntity = getObject(MchAppEntity.class); + mchAppEntity.setAgentNo(getCurrentAgentNo()); + + // app融合搜索,appId appName mchNo mchName + mchAppEntity.addExt("unionSearchId", getValStringDefault("unionSearchId", "")); + + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + mchAppEntity.setSubAgentNoList(subAgentNoList); + } + + IPage pages = mchAppService.selectPage(getIPage(true), mchAppEntity); + + return ApiRes.page(pages); + } + + /** + * @Author: ZhuXiao + * @Description: 新建应用 + * @Date: 10:05 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APP_ADD')") + @MethodLog(remark = "新建应用") + @PostMapping + public ApiRes add() { + MchAppEntity mchAppEntity = getObject(MchAppEntity.class); + if (StringUtils.isEmpty(mchAppEntity.getMchNo())) { + throw new BizException("商户号不能为空"); + } + MchInfo mchInfo = mchInfoService.getById(mchAppEntity.getMchNo()); + if (mchInfo == null || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + mchAppEntity.setMchNo(mchInfo.getMchNo()); + mchAppEntity.setAgentNo(getCurrentAgentNo()); + mchAppEntity.setTopAgentNo(mchInfo.getTopAgentNo()); + mchAppEntity.setAppId(SeqKit.getMchAppId()); + //默认设置为审核中 + mchAppEntity.setState(MchAppEntity.AUDIT); + // 如果当前为默认 + if (mchAppEntity.getDefaultFlag() == CS.YES) { + mchAppService.update(new LambdaUpdateWrapper() + .set(MchAppEntity::getDefaultFlag, CS.NO) + .eq(MchAppEntity::getMchNo, mchAppEntity.getMchNo()) + ); + } + + boolean result = mchAppService.save(mchAppEntity); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE); + } + return ApiRes.ok(); + } + + /** + * @Author: ZhuXiao + * @Description: 应用详情 + * @Date: 10:13 2021/6/16 + */ + @PreAuthorize("hasAnyAuthority('ENT_MCH_APP_VIEW', 'ENT_MCH_APP_EDIT')") + @GetMapping("/{appId}") + public ApiRes detail(@PathVariable("appId") String appId) { + MchAppEntity mchAppEntity = mchAppService.selectById(appId); + + if (mchAppEntity == null || !mchAppEntity.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + return ApiRes.ok(mchAppEntity); + } + + /** + * @Author: ZhuXiao + * @Description: 更新应用信息 + * @Date: 10:11 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APP_EDIT')") + @MethodLog(remark = "更新应用信息") + @PutMapping("/{appId}") + public ApiRes update(@PathVariable("appId") String appId) { + MchAppEntity mchAppEntity = getObject(MchAppEntity.class); + mchAppEntity.setAppId(appId); + + MchAppEntity dbMchAppEntity = mchAppService.getById(appId); + if (!dbMchAppEntity.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("无权操作!"); + } + if (mchAppEntity.getDefaultFlag() != null && !dbMchAppEntity.getDefaultFlag().equals(mchAppEntity.getDefaultFlag())) { + // 如果修改当前为默认 + if (mchAppEntity.getDefaultFlag() == CS.YES) { + mchAppService.update(new LambdaUpdateWrapper() + .set(MchAppEntity::getDefaultFlag, CS.NO) + .eq(MchAppEntity::getMchNo, dbMchAppEntity.getMchNo()) + ); + }else { + throw new BizException("应用不可修改为非默认!"); + } + } + + boolean result = mchAppService.updateById(mchAppEntity); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + return ApiRes.ok(); + } + + /** + * @Author: ZhuXiao + * @Description: 删除应用 + * @Date: 10:14 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_APP_DEL')") + @MethodLog(remark = "删除应用") + @DeleteMapping("/{appId}") + public ApiRes delete(@PathVariable("appId") String appId) { + MchAppEntity mchAppEntity = mchAppService.getById(appId); + + if (!mchAppEntity.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("无权操作!"); + } + + mchAppService.removeByAppId(appId); + + return ApiRes.ok(); + } + + /** 功能描述: 查询系统公钥 */ + @PreAuthorize("hasAnyAuthority('ENT_MCH_APP_ADD', 'ENT_MCH_APP_EDIT')") + @GetMapping("/sysRSA2PublicKey") + public ApiRes sysRSA2PublicKey() { + return ApiRes.ok(systemYmlConfig.getSysRSA2PublicKey()); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchConfigController.java new file mode 100644 index 0000000..aa49d18 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchConfigController.java @@ -0,0 +1,120 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchConfig; +import com.jeequan.jeepay.service.impl.MchConfigService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 商户配置管理类 + * + * @author zx + * @date 2021-06-16 09:15 + */ +@RestController +@RequestMapping("/api/mchConfig") +public class MchConfigController extends CommonCtrl { + + @Autowired + private MchConfigService mchConfigService; + @Autowired + private MchInfoService mchInfoService; + + /** + * @Author: zx + * @Description: 查询商户配置 + * @Date: 9:59 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_CONFIG_PAGE')") + @GetMapping + public ApiRes list() { + + String groupKey = getValString("groupKey"); + + String mchNo = getValStringRequired("mchNo"); + String mchAppId = getValString("mchAppId"); + String mchApplyId = getValString("mchApplyId"); + + LambdaQueryWrapper queryWrapper = MchConfig.gw() + .eq(MchConfig::getMchNo, mchNo) + .eq(!ObjUtil.isEmpty(mchAppId), MchConfig::getMchAppId, mchAppId) + .eq(!ObjUtil.isEmpty(mchApplyId), MchConfig::getMchApplyId, mchApplyId); + if (StringUtils.isNotBlank(groupKey)) { + queryWrapper.eq(MchConfig::getGroupKey, groupKey); + } + + List list = mchConfigService.list(queryWrapper); + return ApiRes.ok(list); + } + + /** + * @Author: zx + * @Description: 根据configKey查询商户配置 + * @Date: 9:59 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_CONFIG_EDIT')") + @GetMapping("/{configKey}") + public ApiRes get(@PathVariable("configKey") String configKey) { + + MchConfig mchConfig = mchConfigService.getOne(MchConfig.gw().eq(MchConfig::getMchNo, getValStringRequired("mchNo")).eq(MchConfig::getConfigKey, configKey)); + return ApiRes.ok(mchConfig); + } + + /** + * @Author: zx + * @Description: 根据configKey更新商户配置信息 + * @Date: 10:11 2021/6/16 + */ + /*@PreAuthorize("hasAuthority('ENT_MCH_CONFIG_EDIT')") + @MethodLog(remark = "更新商户配置") + @PutMapping("/{configKey}") + public ApiRes updateByConfigKey(@PathVariable("configKey") String configKey) { + MchConfig mchConfig = getObject(MchConfig.class); + mchConfig.setConfigKey(configKey); + + int count = mchConfigService.saveOrUpdateConfig(mchConfig, getCurrentMchNo()); + if(count <= 0) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + return ApiRes.ok(); + }*/ + + /** + * @author: zx + * @Description: 批量更新商户配置信息 + * @Date: 10:11 2021/6/16 + */ + @PreAuthorize("hasAuthority('ENT_MCH_CONFIG_PAGE')") + @MethodLog(remark = "批量更新商户配置信息") + @PutMapping("/{groupKey}") + public ApiRes updateBatch(@PathVariable("groupKey") String groupKey) { + + String params = getValStringRequired("configData"); + + List mchConfigList = JSONArray.parseArray(params, MchConfig.class); + String mchNo = getValStringRequired("mchNo"); + String mchAppId = getValString("mchAppId"); + String mchApplyId = getValString("mchApplyId"); + + int update = mchConfigService.updateBatch(mchConfigList, mchNo, mchAppId, mchApplyId, groupKey); + if (update <= 0) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + + return ApiRes.ok(); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchInfoController.java new file mode 100644 index 0000000..abf6c2e --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchInfoController.java @@ -0,0 +1,221 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.DesensitizedUtil; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.components.mq.model.CleanMchLoginAuthCacheMQ; +import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.PrefixConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.service.impl.MchInfoService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * 商户管理类 + * + * @author pangxiaoyu + * @site https://www.jeequan.com + * @date 2021-06-07 07:15 + */ +@RestController +@RequestMapping("/api/mchInfo") +public class MchInfoController extends CommonCtrl { + + @Autowired private IMQSender mqSender; + @Autowired private SmsManager smsManager; + @Autowired private PrefixConfig prefixConfig; + @Autowired private MchInfoService mchInfoService; + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:14 + * @describe: 商户信息列表 + */ + @PreAuthorize("hasAuthority('ENT_MCH_LIST')") + @GetMapping(value = "") + public ApiRes list() { + MchInfo mchInfo = getObject(MchInfo.class); + // 仅查询当前服务商数据 + mchInfo.setAgentNo(getCurrentAgentNo()); + // 扩展员仅查询自己的数据 + if (getCurrentUser().isEpUser()){ + mchInfo.setCreatedUid(getCurrentUser().getSysUser().getSysUserId()); + } + Page listPage = mchInfoService.getListPage(getIPage(), mchInfo); + return ApiRes.page(listPage); + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:14 + * @describe: 新增商户信息 + */ + @PreAuthorize("hasAuthority('ENT_MCH_INFO_ADD')") + @MethodLog(remark = "新增商户") + @PostMapping + public ApiRes add() { + AgentInfo pAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + // 当前服务商是否允许发展下级商户 + if (pAgentInfo.getAddMchFlag() != CS.YES) { + throw new BizException("当前服务商不可发展下级商户"); + } + MchInfo mchInfo = getObject(MchInfo.class); + // 获取传入的商户登录名、登录密码 + String loginPassword = getValString("loginPassword"); + Byte isNotify = getValByteRequired("isNotify"); + if (StringUtils.isBlank(loginPassword)) { + loginPassword = null; + } + mchInfo.setMchNo(SeqKit.genMchNo()); + + // 当前服务商 + mchInfo.setAgentNo(getCurrentAgentNo()); + mchInfo.setTopAgentNo(agentInfoService.queryTopAgentNo(getCurrentAgentNo())); + // 商户类型 + mchInfo.setType(MchInfo.TYPE_ISVSUB); + // 商户级别 + mchInfo.setMchLevel(MchInfo.MCH_LEVEL_M0); + // 商户退款权限 + JSONArray refundModeArray = new JSONArray(); + refundModeArray.add(MchInfo.REFUND_MODEL_PLAT); + refundModeArray.add(MchInfo.REFUND_MODEL_API); + mchInfo.setRefundMode(refundModeArray); + + // 当前登录用户信息 + SysUser sysUser = getCurrentUser().getSysUser(); + mchInfo.setCreatedUid(sysUser.getSysUserId()); + mchInfo.setCreatedBy(sysUser.getRealname()); + + mchInfoService.addMch(mchInfo, loginPassword); + // 发送短信通知 + if (isNotify == CS.YES) { + smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(mchInfo.getContactTel(), mchInfo.getLoginUsername(), loginPassword)); + } + return ApiRes.ok(); + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:14 + * @describe: 删除商户信息 + */ + @PreAuthorize("hasAuthority('ENT_MCH_INFO_DEL')") + @MethodLog(remark = "删除商户") + @RequestMapping(value="/{mchNo}", method = RequestMethod.DELETE) + public ApiRes delete(@PathVariable("mchNo") String mchNo) { + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (mchInfo == null) { + throw new BizException("该商户不存在"); + } + if (!mchInfo.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + List userIdList = mchInfoService.removeByMchNo(mchNo); + + // 推送mq删除redis用户缓存 + mqSender.send(CleanMchLoginAuthCacheMQ.build(userIdList)); + + // 推送mq到目前节点进行更新数据 + mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchNo, null)); + return ApiRes.ok(); + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:14 + * @describe: 更新商户信息 + */ + @PreAuthorize("hasAuthority('ENT_MCH_INFO_EDIT')") + @MethodLog(remark = "更新商户信息") + @RequestMapping(value="/{mchNo}", method = RequestMethod.PUT) + public ApiRes update(@PathVariable("mchNo") String mchNo) { + + //获取查询条件 + MchInfo mchInfo = getObject(MchInfo.class); + mchInfo.setMchNo(mchNo); //设置商户号主键 + + mchInfo.setType(null); //防止变更商户类型 + mchInfo.setAgentNo(null); +// mchInfo.setIsvNo(null); // 防止变更服务商ID + mchInfo.setTopAgentNo(null); // 防止变更顶级代理ID + mchInfo.setRefundMode(null); // 防止变更退款权限 + mchInfo.setLoginUsername(null); // 防止修改用户登录名 + + + MchInfo dbRecord = mchInfoService.getById(mchNo); + if (dbRecord == null || !getCurrentAgentNo().equals(dbRecord.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 状态禁止操作:平台停用 -> 启用 + if (mchInfo.getState() != null && mchInfo.getState() == CS.YES && dbRecord.getState() == MchInfo.STATE_NO_MGR) { + throw new BizException("商户状态停用,请联系运营平台处理"); + } + // 数据库状态为 由平台停用的,不可修改 + if (dbRecord.getState() == MchInfo.STATE_NO_MGR) { + mchInfo.setState(null); + } + + + boolean resetPass = getReqParamJSON().getBooleanValue("resetPass"); + String confirmPwd = null; + if(resetPass){ + confirmPwd = getReqParamJSON().getBoolean("defaultPass") ? null : Base64.decodeStr(getValStringRequired("confirmPwd")); + } + + // 更新商户 & 得到需要删除的商户用户ID的记录 + Set removeCacheUserIdList = mchInfoService.updateMch(mchInfo, resetPass, confirmPwd); + + // 推送mq删除redis用户认证信息 + if (!removeCacheUserIdList.isEmpty()) { + mqSender.send(CleanMchLoginAuthCacheMQ.build(new ArrayList<>(removeCacheUserIdList))); + } + + // 推送mq到目前节点进行更新数据 + mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchNo, null)); + + return ApiRes.ok(); + } + + /** + * @author: pangxiaoyu + * @date: 2021/6/7 16:14 + * @describe: 查询商户信息 + */ + @PreAuthorize("hasAnyAuthority('ENT_MCH_INFO_VIEW', 'ENT_MCH_INFO_EDIT')") + @RequestMapping(value="/{mchNo}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("mchNo") String mchNo) { + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (mchInfo == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + if (mchInfo.getState() == MchInfo.STATE_NO_MGR) { + mchInfo.setState(CS.NO); + } + + return ApiRes.ok(mchInfo); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchModifyApplymentController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchModifyApplymentController.java new file mode 100644 index 0000000..9c14c82 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchModifyApplymentController.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * TODO + * + * @author crystal + * @date 2023/12/27 15:36 + */ +@RestController +@RequestMapping("/api/mchModifyApplyment") +public class MchModifyApplymentController extends CommonCtrl { + + @Autowired private MchModifyApplymentService modifyApplymentService; + + + @GetMapping + public ApiRes list() { + MchModifyApplymentEntity modifyApplyment = getObject(MchModifyApplymentEntity.class); + JSONObject paramJSON = getReqParamJSON(); + //查询该服务商下的所有用户数据(包括自己和下级服务商) + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + List mchInfoList = mchInfoService.list(MchInfo.gw() + .in(MchInfo::getAgentNo, subAgentNoList) + .eq(MchInfo::getState,1)) + .stream() + .map(MchInfo::getMchNo).collect(Collectors.toList()); + modifyApplyment.setMchInfoList(mchInfoList); + Page pages = modifyApplymentService.pageList(getIPage(), modifyApplyment,paramJSON); + return ApiRes.page(pages); + } + + @GetMapping("/result/{modifyApplyId}") + public ApiRes getResult(@PathVariable("modifyApplyId") String modifyApplyId) { + modifyApplymentService.getResult(modifyApplyId); + + return ApiRes.ok(); + } + + @PreAuthorize("hasAuthority('ENT_MCH_APPLYMENT_VIEW')") + @GetMapping("/{recordId}") + public ApiRes detail(@PathVariable("recordId") String recordId) { + Byte originData = getValByteDefault("originData", CS.NO); + MchModifyApplymentEntity record; + if (CS.NO == originData) { + record = modifyApplymentService.getInfoById(recordId); + } else { + record = modifyApplymentService.getById(recordId); + } + + return ApiRes.ok(record); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchPayInterfaceConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchPayInterfaceConfigController.java new file mode 100644 index 0000000..3237e83 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchPayInterfaceConfigController.java @@ -0,0 +1,89 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.db.entity.MchAppEntity; +import com.jeequan.jeepay.db.entity.PayInterfaceConfig; +import com.jeequan.jeepay.service.impl.MchAppService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.PayInterfaceConfigService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.HashSet; +import java.util.Set; + +/** + * 商户支付接口配置类 + * + * @author zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("/api/mch/payConfigs") +public class MchPayInterfaceConfigController extends CommonCtrl { + + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private MchInfoService mchInfoService; + @Autowired + private MchAppService mchAppService; + @Autowired + private SysConfigService sysConfigService; + @Autowired + private IMQSender mqSender; + + + /** + * 查询支付宝商户授权URL + **/ + @GetMapping("/alipayIsvsubMchAuthUrls/{mchAppId}/{isvNo}") + public ApiRes queryAlipayIsvsubMchAuthUrl(@PathVariable("mchAppId") String mchAppId, + @PathVariable("isvNo") String isvNo) { + + MchAppEntity mchAppEntity = mchAppService.getById(mchAppId); + + DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig(); + String authUrl = dbApplicationConfig.genAlipayIsvsubMchAuthUrl(isvNo, mchAppId); + String authQrImgUrl = dbApplicationConfig.genScanImgUrl(authUrl); + + JSONObject result = new JSONObject(); + result.put("authUrl", authUrl); + result.put("authQrImgUrl", authQrImgUrl); + return ApiRes.ok(result); + } + + + /** + * 查询当前应用支持的支付接口 + */ + @PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_ADD' )") + @RequestMapping(value = "ifCodes/{appId}", method = RequestMethod.GET) + public ApiRes getIfCodeByAppId(@PathVariable("appId") String appId) { + + if (mchAppService.lambdaQuery().eq(MchAppEntity::getMchNo, getCurrentAgentNo()).eq(MchAppEntity::getAppId, appId).count() <= 0) { + throw new BizException("商户应用不存在"); + } + + Set result = new HashSet<>(); + + payInterfaceConfigService.lambdaQuery().select(PayInterfaceConfig::getIfCode) + .eq(PayInterfaceConfig::getState, CS.PUB_USABLE) + .eq(PayInterfaceConfig::getInfoId, appId) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .list().forEach(r -> result.add(r.getIfCode())); + + return ApiRes.ok(result); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchVideoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchVideoController.java new file mode 100644 index 0000000..6ceedf7 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/MchVideoController.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.ctrls.AbstractCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchVideoCacheEntity; +import com.jeequan.jeepay.service.impl.MchVideoCacheService; +import com.jeequan.jeepay.thirdparty.service.wxchannel.WechatChannelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/mchVideo") +public class MchVideoController extends AbstractCtrl { + + @Autowired + private WechatChannelService wechatChannelService; + + @Autowired + private MchVideoCacheService mchVideoCacheService; + + @PostMapping("/authTask") + public ApiRes auth() { + String mchNo = getValStringRequired("mchNo"); + JSONObject task = wechatChannelService.createTask(mchNo); + + return ApiRes.ok(task); + } + + @GetMapping("/authTask") + public ApiRes taskResult() { + String taskId = getValStringRequired("taskId"); + JSONObject taskResult = wechatChannelService.queryTask(taskId); + + return ApiRes.ok(taskResult); + } + + @GetMapping("/dataList") + public ApiRes cacheList() { + Page iPage = getIPage(); + + MchVideoCacheEntity mchInfo = getObject(MchVideoCacheEntity.class); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(mchInfo); + + Page page = mchVideoCacheService.page(iPage, wrapper); + return ApiRes.ok(page); + } + + @GetMapping("/randomOne") + public ApiRes randomOne() { + String mchNo = getValStringRequired("mchNo"); + MchVideoCacheEntity result = mchVideoCacheService.getRandomOne(mchNo); + return ApiRes.ok(result); + } + + @DeleteMapping("/{id}") + public ApiRes remove(@PathVariable("id") Long id) { + mchVideoCacheService.removeById(id); + + return ApiRes.ok(); + } + + @PostMapping("/choiceFlag/{id}") + public ApiRes choiceFlag(@PathVariable("id") Long id) { + String choiceFlag = getValStringRequired("choiceFlag"); + mchVideoCacheService.lambdaUpdate() + .eq(MchVideoCacheEntity::getId, id) + .set(MchVideoCacheEntity::getChoiceFlag, choiceFlag) + .update(); + + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/PackageInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/PackageInfoController.java new file mode 100644 index 0000000..bdcc4cc --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/PackageInfoController.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.PackageInfo; +import com.jeequan.jeepay.db.entity.PackageOrder; +import com.jeequan.jeepay.service.impl.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api/packageInfo") +public class PackageInfoController extends CommonCtrl { + + @Autowired private PackageInfoService packageInfoService; + @Autowired private PackageProductService packageProductService; + @Autowired private ProductInfoService productInfoService; + @Autowired private ProductAppService productAppService; + @Autowired private PackageTypeService packageTypeService; + + @RequestMapping(value = "/getPackageList", method = RequestMethod.GET) + @MethodLog(remark = "方案中心列表") + public ApiRes getPackageList() throws BizException { + PackageInfo packageInfo = getObject(PackageInfo.class); + Page page = new Page<>(); + List packageInfoList = packageInfoService.getPackageList(packageInfo.getName(),packageInfo.getState(),packageInfo.getPackageType()); + page.setRecords(packageInfoList); + page.setTotal(packageInfoList.size()); + page.setCurrent(1); + return ApiRes.ok(page); + } + + @RequestMapping(value = "/getPackageById", method = RequestMethod.GET) + @MethodLog(remark = "商户端方案详情") + public ApiRes getPackageById() throws BizException { + //获取查询条件 + PackageInfo packageInfo = getObject(PackageInfo.class); + PackageInfo info = packageInfoService.getPackageById(packageInfo.getPackageId()); + return ApiRes.ok(info); + } + + + @GetMapping("/getPackageOder") + @MethodLog(remark = "开通记录") + public ApiRes getPackageOder(){ + Page page=getIPage(true); + PackageOrder packageOrder = getObject(PackageOrder.class); + // 时间搜索 + Date[] searchDateRange = packageOrder.buildQueryDateRange(); + packageOrder.setFirstDate(searchDateRange[0]); + packageOrder.setLastDate(searchDateRange[1]); + //packageOrder.setCreatedUid(getCurrentUser().getSysUserId()); + //查询该服务商下的所有用户数据(包括自己和下级服务商) + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + List mchInfoList = mchInfoService.list(MchInfo.gw() + .in(MchInfo::getAgentNo, subAgentNoList) + .eq(MchInfo::getState,1)) + .stream() + .map(MchInfo::getMchNo).collect(Collectors.toList()); + packageOrder.setMchInfoList(mchInfoList); + Page result = productAppService.getProductAppList(page, packageOrder); + return ApiRes.ok(result); + } + + @RequestMapping(value = "/getPackageOderById", method = RequestMethod.GET) + @MethodLog(remark = "开通记录详情") + public ApiRes getPackageOderById() throws BizException { + //获取查询条件 + PackageOrder packageOrder = getObject(PackageOrder.class); + PackageOrder serviceById = productAppService.getDetail(packageOrder.getId()); + return ApiRes.ok(serviceById); + } + + @MethodLog(remark = "更新开通记录") + @RequestMapping(value="/{id}", method = RequestMethod.PUT) + public ApiRes update(@PathVariable("id") String id) { + PackageOrder packageOrder = getObject(PackageOrder.class); + packageOrder.setId(id);//设置主键 + packageOrder.setUpdatedAt(new Date()); + packageOrder.setState(1); + productAppService.updateById(packageOrder); + return ApiRes.ok(); + } + + @RequestMapping(value = "/getPackageTypeList", method = RequestMethod.GET) + @MethodLog(remark = "获取所有方案分类列表") + public ApiRes getPackageTypeList() throws BizException { + return ApiRes.ok(packageTypeService.list()); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/TerminalController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/TerminalController.java new file mode 100644 index 0000000..394e5bf --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/TerminalController.java @@ -0,0 +1,140 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.MchStoreTerminalManage; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchStoreTerminal; +import com.jeequan.jeepay.service.impl.MchStoreTerminalService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/*** +* 终端设备管理 +* +* @author terrfly +* +* @date 2022/4/26 17:34 +*/ +@Slf4j +@RestController +@RequestMapping("/api/mchTerminals") +public class TerminalController extends CommonCtrl { + + @Autowired private MchStoreTerminalService mchStoreTerminalService; + @Autowired private MchStoreTerminalManage mchStoreTerminalManage; + + @PreAuthorize("hasAuthority('ENT_TERMINAL_LIST')") + @GetMapping + public ApiRes pages() { + + // 请求参数 + MchStoreTerminal queryObject = getObject(MchStoreTerminal.class); + // 可查看自己和全部下级代理的设备 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + queryObject.setSubAgentNoList(subAgentNoList); + } + IPage page = mchStoreTerminalService.getMchStoreTerminalList(getIPage(), queryObject); + + return ApiRes.page(page); + } + + /** detail */ + @PreAuthorize("hasAuthority( 'ENT_TERMINAL_VIEW' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("recordId") String recordId) { + return ApiRes.ok(mchStoreTerminalService.getById(recordId)); + } + + + + /** add */ + @PreAuthorize("hasAuthority( 'ENT_TERMINAL_ADD' )") + @MethodLog(remark = "添加商户终端信息") + @RequestMapping(value="", method = RequestMethod.POST) + public ApiRes add() { + return mchStoreTerminalManage.add(getObject(MchStoreTerminal.class)); + } + + + /** update */ + @PreAuthorize("hasAuthority( 'ENT_TERMINAL_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.PUT) + @MethodLog(remark = "更新商户终端信息") + public ApiRes update(@PathVariable("recordId") Long recordId) { + + MchStoreTerminal record = getObject(MchStoreTerminal.class); + record.setTrmId(recordId); + return mchStoreTerminalManage.update(record); + } + + + /** update */ + @PreAuthorize("hasAuthority( 'ENT_TERMINAL_EDIT' )") + @RequestMapping(value="/trmDefaults", method = RequestMethod.PUT) + @MethodLog(remark = "更新商户终端默认状态") + public ApiRes updateDefault() { + + return mchStoreTerminalManage.updateDefault(getValLongRequired("trmId"), getValByteRequired("defaultFlag")); + } + + + /** delete */ + @PreAuthorize("hasAuthority('ENT_TERMINAL_DEL')") + @MethodLog(remark = "删除终端") + @RequestMapping(value="/{recordId}", method = RequestMethod.DELETE) + public ApiRes del(@PathVariable("recordId") String recordId) { + mchStoreTerminalService.removeById(recordId); + return ApiRes.ok(); + } + + + /** 报备列表 */ + @PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')") + @RequestMapping(value="channelBindInfos/{recordId}", method = RequestMethod.GET) + public ApiRes channelBindInfos(@PathVariable("recordId") Long recordId) { + + return mchStoreTerminalManage.getChannelBindInfos(recordId); + } + + + /** 终端报备 */ + @PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')") + @MethodLog(remark = "终端报备") + @RequestMapping(value="channelSendup/{recordId}", method = RequestMethod.POST) + public ApiRes channelSendup(@PathVariable("recordId") Long recordId) { + + String ifCode = getValStringRequired("ifCode"); + Byte state = getValByteRequired("state"); // 0 - 取消报备, 1- 申请报备 + + return mchStoreTerminalManage.channelSendup(recordId, ifCode, state); + } + + + /** 修改终端报备信息 */ + @PreAuthorize("hasAuthority('ENT_TERMINAL_SENDUP')") + @MethodLog(remark = "自定义终端报备信息") + @RequestMapping(value="channelBindInfos/{recordId}", method = RequestMethod.POST) + public ApiRes updChannelBindInfos(@PathVariable("recordId") Long recordId) { + + + String ifCode = getValStringRequired("ifCode"); + String channelTrmNo = getValStringDefault("channelTrmNo", ""); // 报备信息 + Byte state = getValByteRequired("state"); + + return mchStoreTerminalManage.updChannelBindInfos(recordId, ifCode, channelTrmNo, state); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/WxMpUserController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/WxMpUserController.java new file mode 100644 index 0000000..e454bdb --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/merchant/WxMpUserController.java @@ -0,0 +1,171 @@ +package com.jeequan.jeepay.agent.ctrl.merchant; + +import cn.hutool.core.lang.UUID; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.google.zxing.WriterException; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.util.CodeImgUtil; +import com.jeequan.jeepay.components.oss.config.OssYmlConfig; +import com.jeequan.jeepay.components.oss.model.OssFileConfig; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.core.model.DBOSSConfig; +import com.jeequan.jeepay.core.model.DBWxMpConfig; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchWxmpUser; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.MchWxmpUserService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.io.File; +import java.io.IOException; + +/** + * 微信公众号提醒配置类 + * + * @author zx + * + * @date 2021-10-15 09:15 + */ +@RestController +@RequestMapping("/api/wxmp") +public class WxMpUserController extends CommonCtrl { + + @Autowired private MchInfoService mchInfoService; + @Autowired private SysConfigService sysConfigService; + @Autowired private MchWxmpUserService mchWxmpUserService; + @Autowired private OssYmlConfig ossYmlConfig; + + /** + * @Author: zx + * @Description: 商户创建微信公众号接收者的显示信息 + * @Date: 2021-10-15 09:15 + */ + @GetMapping("/getWxmpInfo") + public ApiRes getWxmpInfo() { + + MchInfo mchInfo = mchInfoService.getById(getCurrentUser().getSysUser().getBelongInfoId()); + + DBApplicationConfig applicationConfig = sysConfigService.getDBApplicationConfig(); + DBOSSConfig ossConfig = sysConfigService.getOssConfig(); + DBWxMpConfig wxMpConfig = sysConfigService.getDBWxMpConfig(); + if(wxMpConfig == null){ + throw new BizException("未正确配置微信公众号消息配置项"); + } + + String mchAuthRedirectUrl = StringUtils.isBlank(wxMpConfig.getMchAuthRedirectUrl()) ? DBWxMpConfig.DEFAULT_WX_AUTH_DOMAIN : wxMpConfig.getMchAuthRedirectUrl(); + + JSONObject result = new JSONObject(); + String authUrl = DBWxMpConfig.mchAuthUrl + .replace("{{mchAuthRedirectUrl}}", mchAuthRedirectUrl) + .replace("{{mchNo}}", mchInfo.getMchNo()) + .replace("{{appId}}", wxMpConfig.getWxAppId()) + .replace("{{paySiteUrl}}", applicationConfig.getPaySiteUrl()); + + // 文件地址 (xxx/xxx.jpg 格式) + String filePath = ossYmlConfig.getOss().getFilePublicPath() + File.separator + OssFileConfig.BIZ_TYPE.WX_FILE + File.separator; + String fileName = UUID.fastUUID() + ".png"; + + try { + CodeImgUtil.codeImgEncode(filePath, fileName, authUrl, 200, 200); + result.put("authQr", ossConfig.getOssPublicSiteUrl() + File.separator + OssFileConfig.BIZ_TYPE.WX_FILE + File.separator + fileName); + result.put("wxmpQr", wxMpConfig.getWxmpUrl()); + + return ApiRes.ok(result); + } catch (WriterException | IOException e) { + logger.error("", e); + return ApiRes.customFail("获取授权码失败"); + } + } + + /** + * @Author: zx + * @Description: 微信公众号取消关注 + * @Date: 2021-10-15 09:15 + */ + @GetMapping("/unAuth") + public ApiRes unAuth() { + + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(MchWxmpUser::getMchNo, getCurrentAgentNo()); + updateWrapper.set(MchWxmpUser::getSendStatus, MchWxmpUser.SEND_STATE_CLOSE); + boolean updateResult = mchWxmpUserService.update(updateWrapper); + if (!updateResult) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + + return ApiRes.ok(); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 微信公众号消息接收者列表 + */ + @PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_LIST')") + @GetMapping + public ApiRes pages() { + LambdaQueryWrapper gw = MchWxmpUser.gw(); + gw.eq(MchWxmpUser::getMchNo, getCurrentAgentNo()); + + if (StringUtils.isNotBlank(getValString("nickname"))) { + gw.like(MchWxmpUser::getNickname, getValString("nickname")); + } + + IPage page = mchWxmpUserService.page(getIPage(), gw); + //返回数据 + return ApiRes.page(page); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 微信公众号消息接收者修改 + */ + @PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_EDIT')") + @MethodLog(remark = "微信公众号消息接收者修改") + @PutMapping("/{userId}") + public ApiRes update(@PathVariable("userId") Long userId) { + MchWxmpUser mchWxmpUser = getObject(MchWxmpUser.class); + mchWxmpUser.setUserId(userId); + + MchWxmpUser dbRecord = mchWxmpUserService.getById(userId); + if (!getCurrentAgentNo().equals(dbRecord.getMchNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + if(!mchWxmpUserService.updateById(mchWxmpUser)) { + return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "更新失败"); + } + + return ApiRes.ok(); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 微信公众号消息接收者删除 + */ + @PreAuthorize("hasAuthority('ENT_MCH_WXMP_USER_DELETE')") + @MethodLog(remark = "微信公众号消息接收者删除") + @DeleteMapping("/{userId}") + public ApiRes delete(@PathVariable("userId") Long userId) { + if(mchWxmpUserService.remove(MchWxmpUser.gw().eq(MchWxmpUser::getUserId, userId).eq(MchWxmpUser::getMchNo, getCurrentAgentNo()))) { + return ApiRes.ok(); + } + + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_DELETE); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/PayOrderController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/PayOrderController.java new file mode 100644 index 0000000..a497ab6 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/PayOrderController.java @@ -0,0 +1,261 @@ +package com.jeequan.jeepay.agent.ctrl.order; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.JeepayClient; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrderCount; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBOSSConfig; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.export.PayOrderExportExcel; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.exception.JeepayException; +import com.jeequan.jeepay.model.PayOrderQueryReqModel; +import com.jeequan.jeepay.model.PayOrderQueryResModel; +import com.jeequan.jeepay.request.PayOrderQueryRequest; +import com.jeequan.jeepay.response.PayOrderQueryResponse; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.*; + +/** + * 支付订单管理类 + * + * @author zhuxiao + * @site https://www.jeequan.com + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("/api/payOrder") +public class PayOrderController extends CommonCtrl { + + @Autowired private PayOrderService payOrderService; + @Autowired private PayWayService payWayService; + @Autowired private SysConfigService sysConfigService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private OrderProfitSettRecordService orderProfitSettRecordService; + @Autowired private StatsTradeService statsTradeService; + @Autowired private MchAppService mchAppService; + + /** + * @Author: ZhuXiao + * @Description: 订单信息列表 + * @Date: 10:43 2021/5/13 + */ + @PreAuthorize("hasAuthority('ENT_ORDER_LIST')") + @GetMapping + public ApiRes list() { + + PayOrder payOrder = getObject(PayOrder.class); + JSONObject paramJSON = getReqParamJSON(); + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + payOrder.setSubAgentNoList(allSubAgentNoList); + + }else { + if ("onlyOne".equals(payOrder.getAgentNo())) { + payOrder.setAgentNo(getCurrentAgentNo()); + } + } + + IPage pages = payOrderService.listByPage(getIPage(), payOrder, paramJSON); + + return ApiRes.page(pages); + } + + /** + * @Author: ZhuXiao + * @Description: 支付订单信息 + * @Date: 10:43 2021/5/13 + */ + @PreAuthorize("hasAuthority('ENT_PAY_ORDER_VIEW')") + @GetMapping("/{payOrderId}") + public ApiRes detail(@PathVariable("payOrderId") String payOrderId) { + PayOrder payOrder = payOrderService.getDetails(payOrderId); + if (payOrder == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + if (!allSubAgentNoList.contains(payOrder.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + if (StringUtils.isNotBlank(payOrder.getChannelOrderNo())) { + DBOSSConfig ossConfig = sysConfigService.getOssConfig(); + payOrder.addExt("channelOrderNoBar", ossConfig.getOssPublicSiteUrl() + "/bar/" + payOrder.getChannelOrderNo()); + } + + // 查询订单分润情况 + List profitList = orderProfitSettRecordService.getBaseMapper().queryOrderProfitSum(payOrderId, getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT); + payOrder.addExt("profitAmount", profitList.isEmpty() ? null : profitList.get(0).getCalProfitAmount()); + + return ApiRes.ok(payOrder); + } + + + + /** + * @author: xiaoyu + * @date: 2022/2/10 17:00 + * @describe: 订单列表统计 + */ + @PreAuthorize("hasAuthority('ENT_ORDER_COUNT')") + @RequestMapping(value="/count", method = RequestMethod.GET) + public ApiRes count() { + PayOrder payOrder = getObject(PayOrder.class); + List allAgentNoList = null; + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + allAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + }else if ("onlyOne".equals(payOrder.getAgentNo())) { + allAgentNoList = Arrays.asList(getCurrentAgentNo()); + }else { + allAgentNoList = Arrays.asList(payOrder.getAgentNo()); + } + payOrder.setAgentNo(null); + JSONObject paramJSON = getReqParamJSON(); + paramJSON.put("allAgentNoList", allAgentNoList); + // 查询支付、退款金额 笔数 + PayOrderCount orderCount = statsTradeService.selectTotalByTransaction(paramJSON, allAgentNoList); + return ApiRes.ok(orderCount); + } + + /** + * @author: xiaoyu + * @date: 2022/1/14 9:45 + * @describe: 订单列表数据导出 + */ + @RequestMapping(value="/exportExcel", method = RequestMethod.GET) + public void exportExcel() { + try { + JSONObject paramJSON = getReqParamJSON(); + + PayOrder payOrder = getObject(PayOrder.class); + + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + payOrder.setSubAgentNoList(allSubAgentNoList); + + }else if ("onlyOne".equals(payOrder.getAgentNo())) { + payOrder.setAgentNo(getCurrentAgentNo()); + }else { + payOrder.setAgentNo(payOrder.getAgentNo()); + } + payOrder.setAgentNo(null); + + IPage pages = payOrderService.listByPage(getIPage(true), payOrder, paramJSON); + List newList = new LinkedList<>(); + for (PayOrder order:pages.getRecords()) { + JSONObject object = (JSONObject) JSONObject.toJSON(order); + object.put("amount", AmountUtil.convertCent2Dollar(order.getAmount())); + object.put("refundAmount", AmountUtil.convertCent2Dollar(order.getRefundAmount())); + object.put("mchFeeAmount", AmountUtil.convertCent2Dollar(order.getMchFeeAmount())); + object.put("mchOrderFeeAmount", AmountUtil.convertCent2Dollar(order.getMchOrderFeeAmount())); + newList.add(object); + } + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), PayOrderExportExcel.class); + // excel输出 + ExcelUtil.exportExcel(linkedList, "支付订单", "支付订单", PayOrderExportExcel.class, "支付订单", response); + }catch (Exception e) { + logger.error("导出excel失败", e); + throw new BizException("导出订单失败!"); + } + + } + + /** + * @Author: ZhuXiao + * @Description: 订单打印 + * @Date: 10:43 2022/01/13 + */ + @PreAuthorize("hasAuthority('ENT_PAY_ORDER_VIEW')") + @GetMapping("/print/{payOrderId}") + public ApiRes print(@PathVariable("payOrderId") String payOrderId) { + PayOrder payOrder = payOrderService.getById(payOrderId); + if (payOrder == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + if (!payOrder.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + PayOrderInfo4Device printPayOrderInfo = new PayOrderInfo4Device(); + BeanUtil.copyProperties(payOrder, printPayOrderInfo); + + try { + // 查询打印设备 + List deviceList = mchStoreDeviceService.selectAvailableDeviceList(payOrder.getMchNo(), payOrder.getStoreId(), Arrays.asList(DeviceProvideConfig.DEVICE_TYPE_PRINTER)); + if (CollectionUtils.isEmpty(deviceList)) { + return ApiRes.customFail("打印机未配置"); + } + + // 循环调用单个设备 + for (JSONObject deviceParams : deviceList) { + + // 设备类型 + String provider = deviceParams.getString("provider"); + IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class); + + printerService.send(deviceParams, printPayOrderInfo); + } + + return ApiRes.ok(); + } catch (BizException e) { + throw e; + } + } + + @MethodLog(remark = "订单状态刷新") + @PreAuthorize("hasAuthority('ENT_PAY_ORDER_REFRESH')") + @PostMapping("/refresh/{payOrderId}") + public ApiRes refresh(@PathVariable("payOrderId") String payOrderId) { + PayOrder payOrder = payOrderService.getById(payOrderId); + if(payOrder == null){ + throw new BizException("订单数据异常"); + } + if(PayOrder.STATE_ING != payOrder.getState()){ + throw new BizException("订单状态不支持该操作"); + } + MchAppEntity mchAppEntity = mchAppService.getById(payOrder.getAppId()); + PayOrderQueryRequest request = new PayOrderQueryRequest(); + PayOrderQueryReqModel model = new PayOrderQueryReqModel(); + model.setPas(SysConfigService.PLATFORM_API_SECRET); // 通信秘钥 + model.setMchNo(payOrder.getMchNo()); // 商户号 + model.setAppId(payOrder.getAppId()); + model.setPayOrderId(payOrderId); + request.setBizModel(model); + JeepayClient jeepayClient = new JeepayClient(sysConfigService.getDBApplicationConfig().getPaySiteUrl(), mchAppEntity.getAppSecret()); + try { + PayOrderQueryResponse response = jeepayClient.execute(request); + if(response.getCode() != 0){ + throw new BizException(response.getMsg()); + } + PayOrderQueryResModel respData = response.get(); + if(respData.getState() == PayOrder.STATE_SUCCESS){ + return ApiRes.ok("订单刷新成功"); + } + return ApiRes.customFail("订单状态一致,无需当前操作"); + } catch (JeepayException e) { + throw new BizException(e.getMessage()); + } + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/RefundOrderController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/RefundOrderController.java new file mode 100644 index 0000000..272aa50 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/RefundOrderController.java @@ -0,0 +1,161 @@ +package com.jeequan.jeepay.agent.ctrl.order; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.entity.PayOrderCount; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.export.MchRefundOrderExportExcel; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.RefundOrder; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.RefundOrderService; +import com.jeequan.jeepay.service.impl.StatsTradeService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/*** +* 退款订单管理 +* +* @author terrfly +* @date 2022/3/16 20:37 +*/ +@RestController +@RequestMapping("/api/refundOrder") +public class RefundOrderController extends CommonCtrl { + + @Autowired private RefundOrderService refundOrderService; + @Autowired private AgentInfoService agentInfoService; + @Autowired + private StatsTradeService statsTradeService; + + /** + * @Author: ZhuXiao + * @Description: 退款订单信息列表 + * @Date: 10:44 2021/5/13 + */ + @PreAuthorize("hasAuthority('ENT_REFUND_LIST')") + @GetMapping + public ApiRes list() { + + RefundOrder refundOrder = getObject(RefundOrder.class); + JSONObject paramJSON = getReqParamJSON(); + LambdaQueryWrapper wrapper = RefundOrder.gw(); + if (StringUtils.isEmpty(refundOrder.getAgentName())) { + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + wrapper.in(RefundOrder::getAgentNo, allSubAgentNoList); + }else { + if ("onlyOne".equals(refundOrder.getAgentNo())) { + //refundOrder.setAgentNo(getCurrentAgentNo()); + refundOrder.setAgentName(getCurrentAgentNo()); + } + } + + IPage pages = refundOrderService.pageList(getIPage(), wrapper, refundOrder, paramJSON); + setIfName(pages.getRecords()); + + return ApiRes.page(pages); + } + + /** + * @Author: ZhuXiao + * @Description: 退款订单信息 + * @Date: 10:44 2021/5/13 + */ + @PreAuthorize("hasAuthority('ENT_REFUND_ORDER_VIEW')") + @GetMapping("/{refundOrderId}") + public ApiRes detail(@PathVariable("refundOrderId") String refundOrderId) { + RefundOrder refundOrder = refundOrderService.getById(refundOrderId); + if (refundOrder == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + if (!allSubAgentNoList.contains(refundOrder.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + return ApiRes.ok(refundOrder); + } + + + /** + * @author: xiaoyu + * @date: 2022/1/14 9:45 + * @describe: 退款列表数据导出 + */ + @RequestMapping(value="/exportExcel", method = RequestMethod.GET) + public void exportExcel() { + try { + + JSONObject paramJSON = getReqParamJSON(); + LambdaQueryWrapper wrapper = RefundOrder.gw(); + RefundOrder refundOrder = getObject(RefundOrder.class); + + if (StringUtils.isEmpty(refundOrder.getAgentNo())) { + List allSubAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + wrapper.in(RefundOrder::getAgentNo, allSubAgentNoList); + + }else if ("onlyOne".equals(refundOrder.getAgentNo())) { + wrapper.in(RefundOrder::getAgentNo, getCurrentAgentNo()); + }else { + wrapper.in(RefundOrder::getAgentNo, refundOrder.getAgentNo()); + } + refundOrder.setAgentNo(null); + + IPage pages = refundOrderService.pageList(getIPage(true), wrapper, refundOrder, paramJSON); + + List newList = new LinkedList<>(); + for (RefundOrder order:pages.getRecords()) { + JSONObject object = (JSONObject) JSONObject.toJSON(order); + object.put("payAmount", AmountUtil.convertCent2Dollar(order.getPayAmount())); + object.put("refundAmount", AmountUtil.convertCent2Dollar(order.getRefundAmount())); + object.put("refundFeeAmount", AmountUtil.convertCent2Dollar(order.getRefundFeeAmount())); + newList.add(object); + } + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchRefundOrderExportExcel.class); + // excel输出 + ExcelUtil.exportExcel(linkedList, "退款订单", "退款订单", MchRefundOrderExportExcel.class, "退款订单", response); + }catch (Exception e) { + logger.error("导出excel失败", e); + throw new BizException("导出订单失败!"); + } + + } + + /** + * @author: xiaoyu + * @date: 2022/2/10 17:00 + * @describe: 退款列表统计 + */ + @PreAuthorize("hasAuthority('ENT_REFUND_ORDER_COUNT')") + @RequestMapping(value = "/count", method = RequestMethod.GET) + public ApiRes count() { + RefundOrder refundOrder = getObject(RefundOrder.class); + List allAgentNoList = null; + if (StringUtils.isEmpty(refundOrder.getAgentNo())) { + allAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + } else if ("onlyOne".equals(refundOrder.getAgentNo())) { + allAgentNoList = Collections.singletonList(getCurrentAgentNo()); + } else { + allAgentNoList = Collections.singletonList(refundOrder.getAgentNo()); + } + refundOrder.setAgentNo(null); + JSONObject paramJSON = getReqParamJSON(); + paramJSON.put("allAgentNoList", allAgentNoList); + // 查询支付、退款金额 笔数 + PayOrderCount resMap = statsTradeService.selectTotalByTransaction(paramJSON, allAgentNoList); + return ApiRes.ok(resMap); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/TransferOrderController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/TransferOrderController.java new file mode 100644 index 0000000..12bec2e --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/order/TransferOrderController.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.agent.ctrl.order; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.export.MchTransferOrderExportExcel; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.TransferOrderEntity; +import com.jeequan.jeepay.service.impl.TransferOrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + + +/** +* 转账订单api +* +* @author terrfly +* +* @date 2021/8/13 10:52 +*/ +@RestController +@RequestMapping("/api/transferOrders") +public class TransferOrderController extends CommonCtrl { + + @Autowired private TransferOrderService transferOrderService; + + /** list **/ + @PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_LIST')") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class); + // 可查看自己和全部下级代理数据 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + transferOrder.setSubAgentNoList(subAgentNoList); + } + IPage pages = transferOrderService.pageList(getIPage(), transferOrder); + + return ApiRes.page(pages); + } + + /** detail **/ + /*@PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_VIEW')") + @RequestMapping(value="/{recordId}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("recordId") String transferId) { + TransferOrderEntity refundOrder = transferOrderService.queryMchOrder(getCurrentMchNo(), null, transferId); + if (refundOrder == null) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + return ApiRes.ok(refundOrder); + }*/ + + /** + * @author: xiaoyu + * @date: 2022/1/14 9:45 + * @describe: 转账数据导出 + */ + @RequestMapping(value="/exportExcel", method = RequestMethod.GET) + public void exportExcel() { + try { + TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class); + transferOrder.setAgentNo(getCurrentAgentNo()); + IPage pages = transferOrderService.pageList(getIPage(true), transferOrder); + + List newList = new LinkedList<>(); + for (TransferOrderEntity order:pages.getRecords()) { + JSONObject object = (JSONObject) JSONObject.toJSON(order); + object.put("entryType", order.getEntryType().replaceAll("_","")); + object.put("amount", AmountUtil.convertCent2Dollar(order.getAmount())); + newList.add(object); + } + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchTransferOrderExportExcel.class); + // excel输出 + ExcelUtil.exportExcel(linkedList, "转账订单", "转账订单", MchTransferOrderExportExcel.class, "转账订单", response); + }catch (Exception e) { + logger.error("导出excel失败", e); + throw new BizException("导出订单失败!"); + } + + } + + /** + * @author: xiaoyu + * @date: 2023/4/26 14:55 + * @describe: 数据统计 + */ + @PreAuthorize("hasAuthority('ENT_TRANSFER_ORDER_COUNT')") + @RequestMapping(value="/count", method = RequestMethod.GET) + public ApiRes count() { + TransferOrderEntity transferOrder = getObject(TransferOrderEntity.class); + LambdaQueryWrapper wrapper = TransferOrderEntity.gw(); + // 可查看自己和全部下级代理数据 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + transferOrder.setSubAgentNoList(subAgentNoList); + } + + transferOrder.setState(null); + // 条件参数 + transferOrderService.selectParams(wrapper, transferOrder); + Map result = transferOrderService.queryCount(wrapper); + + return ApiRes.ok(result); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/MchPayPassageConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/MchPayPassageConfigController.java new file mode 100644 index 0000000..1feeedb --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/MchPayPassageConfigController.java @@ -0,0 +1,145 @@ +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.MchPayPassageConfigManage; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchPayPassage; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchPayPassageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/**** +* 新版商户支付通道配置ctrl +* +* @author terrfly +* +* @date 2022/3/30 16:37 +*/ +@RestController +@RequestMapping("/api/mch/payPassages") +public class MchPayPassageConfigController extends CommonCtrl { + + @Autowired private MchPayPassageService mchPayPassageService; + @Autowired private MchPayPassageConfigManage mchPayPassageConfigManage; + @Autowired + private MchApplymentService mchApplymentService; + @Autowired + private IMQSender mqSender; + + /** + * 支付方式 <--> 通道配置 + * 左侧列表(支付方式) + * + * **/ + @GetMapping + public ApiRes list() { + + String appId = getValStringRequired("appId"); + String wayCode = getValString("wayCode"); + String wayName = getValString("wayName"); + String unionSearchId = getValString("unionSearchId"); + + return mchPayPassageConfigManage.queryPaywayList(appId, wayCode, wayName, null, unionSearchId, getIPage()); + } + + + /** + * 支付方式 <--> 通道配置 + * 右侧列表(可用的支付接口) + * + * **/ + @GetMapping("/availablePayInterface/{appId}/{wayCode}") + public ApiRes availablePayInterface(@PathVariable("appId") String appId, @PathVariable("wayCode") String wayCode) { + + return mchPayPassageConfigManage.availablePayInterface(appId, wayCode); + } + + + /** + * 更新商户使用的通道信息 + */ + @PostMapping("/mchPassage") + @MethodLog(remark = "更新商户支付通道") + public ApiRes updatePassage() { + + String appId = getValStringRequired("appId"); + String ifCode = getValStringRequired("ifCode"); + String wayCode = getValStringRequired("wayCode"); + Byte state = getValByteRequired("state"); + + mchPayPassageService.updateMchPassageState(appId, wayCode, ifCode, state); + return ApiRes.ok(); + + } + + /** + * 查询商户应用支付通道是否配置 + * 用于进件成功一键配置到应用,点击按钮时检查进件记录中包含的支付方式是否在该应用下已配置其他渠道 + */ + @GetMapping("/exist/{applyId}/{appId}") + public ApiRes exist(@PathVariable("applyId") String applyId, @PathVariable("appId") String appId) { + + MchApplyment tbMchApplyment = mchApplymentService.getById(applyId); + if (tbMchApplyment == null || tbMchApplyment.getState() != MchApplyment.STATE_SUCCESS) { + return ApiRes.customFail("进件记录不存在或进件状态未成功"); + } + + // 获取当前进件记录费率配置 + ApplymentBasicInfo applymentBasicInfo = JSONObject.parseObject(tbMchApplyment.getApplyDetailInfo(), ApplymentBasicInfo.class); + // 费率 + List paywayFeeList = applymentBasicInfo.getPaywayFeeList(); + + // 费率为空,进件成功一键配置到应用将不执行配置费率和通道,可直接返回 + if (CollUtil.isEmpty(paywayFeeList)) { + return ApiRes.ok(); + } + + // 获取费率配置的支付方式 + List wayCodeList = new ArrayList<>(); + paywayFeeList.forEach(paywayFee -> { + wayCodeList.add(paywayFee.getWayCode()); + }); + + // 支付方式已配置其他渠道 + List payPassages = mchPayPassageService.list(MchPayPassage.gw() + .eq(MchPayPassage::getAppId, appId) + .ne(MchPayPassage::getIfCode, tbMchApplyment.getIfCode()) + .in(MchPayPassage::getWayCode, wayCodeList)); + + if (CollUtil.isNotEmpty(payPassages)) { + return ApiRes.ok(JsonKit.newJson("existMchPayPassage", CS.YES)); + } + + return ApiRes.ok(); + } + + /** + * 进件成功一键配置到应用,更新商户支付通道 + */ + @MethodLog(remark = "进件成功,一键配置商户支付信息") + @PostMapping("/applyment/{applyId}/{appId}") + public ApiRes updateMchPayPassageByApplyment(@PathVariable("applyId") String applyId, @PathVariable("appId") String appId) { + +// AutoConfigMchAppPayInfoResult result = mchApplymentService.autoConfigMchAppPayInfo(applyId, appId, getValByteRequired("isOverWrite") == CS.YES); +// +// if (StringUtils.isNotBlank(result.getErrMsg())) { +// return ApiRes.customFail(result.getErrMsg()); +// } + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayConfigController.java new file mode 100644 index 0000000..473cc2a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayConfigController.java @@ -0,0 +1,282 @@ +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.IsvUserConn; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.IsvInfoService; +import com.jeequan.jeepay.service.impl.MchAppService; +import com.jeequan.jeepay.service.impl.PayInterfaceConfigService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/*** + * 支付配置 + * + * @author terrfly + * + * @date 2022/3/21 0:13 + */ +@RestController +@RequestMapping("/api/payConfig") +public class PayConfigController extends CommonCtrl { + + @Autowired + private MchAppService mchAppService; + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private IsvInfoService isvInfoService; + + /** + * 查询可用的支付接口 + *

+ * 使用功能项目: 参数及费率的填写 + * 服务商查询全部支付接口 + * 服务商查询服务商开启的支付接口 + **/ + @PreAuthorize("hasAnyAuthority('ENT_PC', 'ENT_AGENT_RATE_CONFIG', 'ENT_MCH_APPLYMENT')") + @GetMapping("/ifCodes") + public ApiRes ifCodes() { + + // 搜索条件 + String ifName = getValString("ifName"); + + String infoId = getValStringRequired("infoId"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 + + // 支付接口列表 + LambdaQueryWrapper lambdaQueryWrapper = PayInterfaceDefine.gw(); + lambdaQueryWrapper.eq(PayInterfaceDefine::getState, CS.YES); // 查询可用的支付接口列表 + + lambdaQueryWrapper.like(StringUtils.isNotEmpty(ifName), PayInterfaceDefine::getIfName, ifName); + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + Map ifCodeMap = new HashMap<>(); + + // 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】 + if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) || + RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || + RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode) + ) { + + ifCodeMap = isvInfoService.getIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), CS.YES); + List ifCodeList = new ArrayList<>(ifCodeMap.keySet()); + + if (ifCodeList.isEmpty()) { // 没有可用的接口 + return ApiRes.ok(ifCodeList); + } + lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList); + + } else if (RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)) { // 服务商进件 + // 查询 当前服务商 开通的 + ifCodeMap = isvInfoService.getIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), null); + + if (ifCodeMap.isEmpty()) { // 没有可用的接口 + return ApiRes.ok(Collections.emptyList()); + } + + lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeMap.keySet()); + lambdaQueryWrapper.eq(PayInterfaceDefine::getIsSupportApplyment, CS.YES); // 查询支持进件的接口 + } + + + final List list = new ArrayList<>(); + lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt); + final Map finalMap = ifCodeMap; + payInterfaceDefineService.list(lambdaQueryWrapper).forEach(item -> { + // 如果服务商上级配置的开启进件为关闭,那么最终展示的列表中显示的是否开启进件也为关闭 + IsvUserConn ifCodeInfo = finalMap.get(item.getIfCode()); + boolean isEnabled = ifCodeInfo.getStatus() == CS.YES && ifCodeInfo.getConfigStatus() == CS.YES; + item.addExt("configState", ifCodeInfo.getStatus()); + + item.setState(isEnabled ? CS.YES : CS.NO); + list.add(item); + }); + + return ApiRes.ok(list); + } + + + /** + * 查询已经配置的参数信息 + **/ + @PreAuthorize("hasAuthority('ENT_MCH_APP_PAY_CONFIG')") + @GetMapping(value = "/interfaceSavedConfigs") + public ApiRes interfaceSavedConfigs() { + + String ifCode = getValStringRequired("ifCode"); // ifCode + String infoId = getValStringRequired("infoId"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 + + PayInterfaceDefine payInterfaceDefine = payInterfaceDefineService.getById(ifCode); + + String infoType = null; + JSONArray ifDefineArray = null; + + Byte mchType = null; // 商户类型 + Byte isvIsOpenApplyment = 0; // 服务商是否开启进件 + + // 服务商 配置商户应用信息 + if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)) { + infoType = CS.SYS_ROLE_TYPE.MCH_APP; + + MchInfo mchInfo = mchInfoService.getById(mchAppService.getById(infoId).getMchNo()); + mchType = mchInfo.getType(); + + if (mchType == CS.MCH_TYPE_NORMAL) { + ifDefineArray = JSON.parseArray(payInterfaceDefine.getNormalMchParams()); + } else { + ifDefineArray = JSON.parseArray(payInterfaceDefine.getIsvsubMchParams()); + } + } + // 服务商 配置下级服务商信息 + else if (RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)) { + infoType = CS.SYS_ROLE_TYPE.AGENT; + + if ("CURRENTAGENT".equals(infoId)) { + infoId = getCurrentAgentNo(); + } + AgentInfo agentInfo = agentInfoService.getById(infoId); + if (agentInfo != null && StringUtils.isNotBlank(agentInfo.getIsvNo())) { + PayInterfaceConfig isvIfConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, agentInfo.getIsvNo(), ifCode); + isvIsOpenApplyment = isvIfConfig != null ? isvIfConfig.getIsOpenApplyment() : 0; + } + } + + // 查询已经配置的信息 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(infoType, infoId, ifCode); + + if (payInterfaceConfig == null) { + payInterfaceConfig = new PayInterfaceConfig(); + } + + // 处理脱敏数据 + if (StringUtils.isNotEmpty(payInterfaceConfig.getIfParams())) { + + if (RateConfig.CONFIG_MODE_MGRISV.equals(configMode)) { + IsvParams isvParams = IsvParams.factory(ifCode, payInterfaceConfig.getIfParams()); + if (isvParams != null) { + payInterfaceConfig.setIfParams(isvParams.deSenData()); + } + } else if (RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)) { + if (mchType == CS.MCH_TYPE_NORMAL) { + NormalMchParams isvParams = NormalMchParams.factory(ifCode, payInterfaceConfig.getIfParams()); + if (isvParams != null) { + payInterfaceConfig.setIfParams(isvParams.deSenData()); + } + } else { + } + } + } + + payInterfaceConfig.addExt("ifDefineArray", ifDefineArray); + payInterfaceConfig.addExt("mchType", mchType); + payInterfaceConfig.addExt("configPageType", payInterfaceDefine.getConfigPageType()); + payInterfaceConfig.addExt("isSupportApplyment", payInterfaceDefine.getIsSupportApplyment()); // 支付接口是否支持进件 + payInterfaceConfig.addExt("isvIsOpenApplyment", isvIsOpenApplyment); // 上级服务商是否开启进件 + return ApiRes.ok(payInterfaceConfig); + } + + + /** + * 更新支付参数 + **/ + @PreAuthorize("hasAuthority('ENT_MCH_APP_PAY_CONFIG')") + @PostMapping("/interfaceParams") + @MethodLog(remark = "更新支付参数") + public ApiRes saveOrUpdate() { + + PayInterfaceConfig payInterfaceConfig = getObject(PayInterfaceConfig.class); + + String configMode = payInterfaceConfig.extv().getString("configMode"); // 设置类型 + + String infoType = null; + + + if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)) { + infoType = CS.SYS_ROLE_TYPE.MCH_APP; + } + // 服务商 配置下级服务商 + else if (RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)) { + infoType = CS.SYS_ROLE_TYPE.AGENT; + + if ("CURRENTAGENT".equals(payInterfaceConfig.getInfoId())) { + payInterfaceConfig.setInfoId(getCurrentAgentNo()); + } + } + + payInterfaceConfig.setInfoType(infoType); + + //添加更新者信息 + Long userId = getCurrentUser().getSysUser().getSysUserId(); + String realName = getCurrentUser().getSysUser().getRealname(); + payInterfaceConfig.setUpdatedUid(userId); + payInterfaceConfig.setUpdatedBy(realName); + + //根据 服务商号、接口类型 获取商户参数配置 + PayInterfaceConfig dbRecoed = payInterfaceConfigService.getByInfoIdAndIfCode(payInterfaceConfig.getInfoType(), payInterfaceConfig.getInfoId(), payInterfaceConfig.getIfCode()); + //若配置存在,为saveOrUpdate添加ID,第一次配置添加创建者 + if (dbRecoed != null) { + payInterfaceConfig.setId(dbRecoed.getId()); + + // 合并支付参数 + payInterfaceConfig.setIfParams(StringKit.marge(dbRecoed.getIfParams(), payInterfaceConfig.getIfParams(), dbRecoed.getIfCode())); + } else { + payInterfaceConfig.setCreatedUid(userId); + payInterfaceConfig.setCreatedBy(realName); + } + + boolean result = payInterfaceConfigService.saveOrUpdate(payInterfaceConfig); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYSTEM_ERROR, "配置失败"); + } + + return ApiRes.ok(); + } + + /** + * 查询商户应用支付参数、费率是否配置 + * 用于发起进件 自动配置到应用时的提示 + */ + @GetMapping("/existPayParams/{appId}/{ifCode}") + public ApiRes existPayParams(@PathVariable("appId") String appId, @PathVariable("ifCode") String ifCode) { + +// Integer range = getValInteger("range"); +// String mccCode = getValString("mccCode"); +// String isvNo = getValString("isvNo"); +// +// // 应用参数配置 +// PayInterfaceConfig interfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP, appId, ifCode); +// if (interfaceConfig == null) { +// return ApiRes.ok(); +// } +// +// if (StringUtils.isNotBlank(interfaceConfig.getIfParams()) && !interfaceConfig.getIfParams().equals("{}")) { +// return ApiRes.ok(JsonKit.newJson("existMchParams", CS.YES)); +// } +// +// // 费率配置 +// Map paywayFeeMap = rateConfigService.queryPaywayFeeMap(appId + "_" + RateConfig.MCHRATE, CS.SYS_ROLE_TYPE.MCH_APP, ifCode, range, mccCode, isvNo); +// if (paywayFeeMap != null && StringUtils.isNotBlank(interfaceConfig.getIfParams()) && !interfaceConfig.getIfParams().equals("{}")) { +// return ApiRes.ok(JsonKit.newJson("existMchParams", CS.YES)); +// } + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayInterfaceDefineController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayInterfaceDefineController.java new file mode 100644 index 0000000..128b36c --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayInterfaceDefineController.java @@ -0,0 +1,58 @@ +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.service.impl.PayInterfaceDefineService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 支付接口定义管理类 + * + * @author zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/payIfDefines") +public class PayInterfaceDefineController extends CommonCtrl { + + @Autowired private PayInterfaceDefineService payInterfaceDefineService; + + /** + * @Author: ZhuXiao + * @Description: list + * @Date: 15:51 2021/4/27 + */ + @GetMapping + public ApiRes list() { + + PayInterfaceDefine queryRecord = getObject(PayInterfaceDefine.class); + + LambdaQueryWrapper lambdaQueryWrapper = PayInterfaceDefine.gw(); + lambdaQueryWrapper.eq(queryRecord.getState() != null , PayInterfaceDefine::getState, queryRecord.getState()); + lambdaQueryWrapper.eq(queryRecord.getIsSupportApplyment() != null , PayInterfaceDefine::getIsSupportApplyment, queryRecord.getIsSupportApplyment()); + + lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt); + List list = payInterfaceDefineService.list(lambdaQueryWrapper); + return ApiRes.ok(list); + } + + /** + * @Author: ZhuXiao + * @Description: detail + * @Date: 15:51 2021/4/27 + */ + @GetMapping("/{ifCode}") + public ApiRes detail(@PathVariable("ifCode") String ifCode) { + return ApiRes.ok(payInterfaceDefineService.getById(ifCode)); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayWayController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayWayController.java new file mode 100644 index 0000000..8c4affc --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/PayWayController.java @@ -0,0 +1,59 @@ +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.PayWay; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 支付方式配置类 + * + * @author zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("/api/payWays") +public class PayWayController extends CommonCtrl { + + @Autowired PayWayService payWayService; + @Autowired MchPayPassageService mchPayPassageService; + @Autowired PayOrderService payOrderService; + @Autowired MchInfoService mchInfoService; + @Autowired PayInterfaceConfigService payInterfaceConfigService; + + /** + * @Author: ZhuXiao + * @Description: list + * @Date: 15:52 2021/4/27 + */ + @PreAuthorize("hasAuthority('ENT_PAY_ORDER_SEARCH_PAY_WAY')") + @GetMapping + public ApiRes list() { + + + PayWay queryObject = getObject(PayWay.class); + + LambdaQueryWrapper condition = PayWay.gw(); + if(StringUtils.isNotEmpty(queryObject.getWayCode())){ + condition.like(PayWay::getWayCode, queryObject.getWayCode()); + } + if(StringUtils.isNotEmpty(queryObject.getWayName())){ + condition.like(PayWay::getWayName, queryObject.getWayName()); + } + condition.orderByAsc(PayWay::getWayCode); + + IPage pages = payWayService.page(getIPage(true), condition); + + return ApiRes.page(pages); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/QualificationDefineController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/QualificationDefineController.java new file mode 100644 index 0000000..65b3f00 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/QualificationDefineController.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.QualificationDefineEntity; +import com.jeequan.jeepay.service.impl.QualificationDefineService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RequestMapping("/api/qualificationDefine") +@RestController +public class QualificationDefineController extends CommonCtrl { + + @Autowired + private QualificationDefineService qualificationDefineService; + + @PostMapping("/save") + public ApiRes save() { + QualificationDefineEntity entity = getObject(QualificationDefineEntity.class); + boolean save = qualificationDefineService.save(entity); + + return ApiRes.ok(save); + } + + @GetMapping("/page") + public ApiRes page() { + Page iPage = getIPage(false); + QualificationDefineEntity condition = getObject(QualificationDefineEntity.class); + qualificationDefineService.lambdaQuery().setEntity(condition).page(iPage); + + return ApiRes.ok(iPage); + } + + @GetMapping("/{code}") + public ApiRes one(@PathVariable String code) { + QualificationDefineEntity one = qualificationDefineService.lambdaQuery().eq(QualificationDefineEntity::getCode, code).one(); + return ApiRes.ok(one); + } + + @DeleteMapping("/{code}") + public ApiRes del(@PathVariable String code) { + qualificationDefineService.removeById(code); + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/RateConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/RateConfigController.java new file mode 100644 index 0000000..8820e0f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/payconfig/RateConfigController.java @@ -0,0 +1,657 @@ + +package com.jeequan.jeepay.agent.ctrl.payconfig; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.converter.BaseConverter; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.model.RateConfigSimple; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/*** + * 费率配置信息 + * + * @author terrfly + * + * @date 2022/3/21 0:13 + */ +@RestController +@RequestMapping("/api/rateConfig") +public class RateConfigController extends CommonCtrl { + + @Autowired private MchAppService mchAppService; + @Autowired private RateConfigService rateConfigService; + @Autowired private PayWayService payWayService; + @Autowired private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private BaseConverter baseConverter; + @Autowired + private RateConfigV2Service rateConfigV2Service; + + + /** 查询可用的支付接口 **/ + @GetMapping("/ifCodes") + public ApiRes ifCodes() { + + // 搜索条件 + String ifName = getValString("ifName"); + + String infoId = getValStringRequired("infoId"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 + + // 支付接口列表 + LambdaQueryWrapper lambdaQueryWrapper = PayInterfaceDefine.gw(); + lambdaQueryWrapper.eq(PayInterfaceDefine::getState, CS.YES); // 查询可用的支付接口列表 + + lambdaQueryWrapper.like(StringUtils.isNotEmpty(ifName), PayInterfaceDefine::getIfName, ifName); + + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + // 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】 + if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) || + RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)|| + RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode) + ){ + + List ifCodeList = new ArrayList<>(); + payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode) + .eq(PayInterfaceConfig::getInfoId, agentInfo.getIsvNo()) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(PayInterfaceConfig::getState, CS.YES) + ).forEach(r -> ifCodeList.add(r.getIfCode())); + + if(ifCodeList.isEmpty()){ // 没有可用的接口 + return ApiRes.ok(ifCodeList); + } + lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList); + + }else if( RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode) ){ // 服务商进件 + + + // 查询服务商开通的 + List ifCodeList = new ArrayList<>(); + List result = payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode) + .eq(PayInterfaceConfig::getInfoId, agentInfo.getIsvNo()) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(PayInterfaceConfig::getState, CS.YES)); + + for (PayInterfaceConfig payInterfaceConfig : result) { + ifCodeList.add(payInterfaceConfig.getIfCode()); + } + + if(ifCodeList.isEmpty()){ // 没有可用的接口 + return ApiRes.ok(ifCodeList); + } + + // 查询服务商配置费率的支付接口 + Set agentIfCodes = new HashSet<>(); + rateConfigService.lambdaQuery() + .select(RateConfig::getIfCode) + .eq(RateConfig::getInfoId, RateConfig.appendInfoByAgent(getCurrentAgentNo())) + .eq(RateConfig::getInfoType, CS.SYS_ROLE_TYPE.AGENT) + .in(RateConfig::getIfCode, ifCodeList) + .list().forEach(r -> agentIfCodes.add(r.getIfCode())); + + // + Collection ifCodeList1 = CollUtil.intersection(ifCodeList, agentIfCodes); + ifCodeList = new ArrayList<>(ifCodeList1); + + if(ifCodeList.isEmpty()){ // 没有可用的接口 + return ApiRes.ok(ifCodeList); + } + + lambdaQueryWrapper.in(PayInterfaceDefine::getIfCode, ifCodeList); + + } + + + lambdaQueryWrapper.orderByAsc(PayInterfaceDefine::getCreatedAt); + List list = payInterfaceDefineService.list(lambdaQueryWrapper); + return ApiRes.ok(list); + } + + + /** 查询所有可配置的支付方式 payways **/ + @GetMapping("/payways") + public ApiRes payways() { + + String ifCode = getValStringRequired("ifCode"); // ifCode +// String infoId = getValStringRequired("infoId"); // infoId +// String isvNo = getValStringRequired("isvNo"); // infoId + String isvNo = getValStringDefault("isvNo", "V1703659196"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 + Integer range = getValInteger("range"); + String mccCode = getValString("mccCode"); + + String mchAppId = getValString("appId"); + if (!ObjUtil.isEmpty(mchAppId)) { + MchAppEntity mchApp = mchAppService.getById(mchAppId); + range = mchApp.getRange(); + mccCode = mchApp.getMccCode(); + } + + // 商户服务商或者服务商的父ID (用于过滤掉关闭的支付方式) + String belongAgentNo = null; + + // 是否仅显示 支持进件的支付方式(用作进件使用) + boolean isOnlyApplymentSupport = false; + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + belongAgentNo = agentInfo.getAgentNo(); + + // 进件模式 + if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){ + isOnlyApplymentSupport = true; + } + + IPage pages = payWayService.queryWayListByRate(ifCode, isvNo, belongAgentNo, isOnlyApplymentSupport, range, mccCode, isvNo); + return ApiRes.page(pages); + } + + + + /** 查询当前已经配置的列表 **/ + @GetMapping(value="/savedMapData") + public ApiRes savedMapData() { + + String ifCode = getValStringRequired("ifCode"); // ifCode + String infoId = getValStringRequired("infoId"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 +// String isvNo = getValStringRequired("isvNo"); // 设置类型 + String isvNo = getValStringDefault("isvNo", "V1703659196"); // 设置类型 + Integer range = getValInteger("range"); + String mccCode = getValString("mccCode"); + + String mchAppId = getValString("appId"); + if (!ObjUtil.isEmpty(mchAppId)) { + MchAppEntity mchApp = mchAppService.getById(mchAppId); + range = mchApp.getRange(); + mccCode = mchApp.getMccCode(); + } + + // 配置商户费率 || 服务商进件模式 + if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) || RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){ + Map> result = new HashMap<>(); + + String mchNo = ""; + String applyId = ""; + + // 进件模式 : infoId = applyId_mchNo 的拼接方式。 + if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){ + applyId = infoId.split("_")[0]; + mchNo = infoId.split("_")[1]; + } else { +// MchAppEntity mchAppEntity = mchAppService.getById(infoId); +// mchNo = mchAppEntity.getMchNo(); + mchNo = infoId; + } + + Map mchRateMap = null; + // 查询已经配置的信息 + if(RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)){ // 运营平台进件模式 +// mchRateMap = rateConfigService.queryPaywayFeeMapByApplyment(applyId); + // 此处费率不从商户信息里面取了 + mchRateMap = rateConfigService.queryPaywayFeeMap(mchNo, CS.SYS_ROLE_TYPE.MCH_APPLYMENT, ifCode, range, mccCode, isvNo); + }else{ + mchRateMap = rateConfigService.queryPaywayFeeMap(infoId + "_" + RateConfig.MCHRATE, commonGetInfoType(configMode), ifCode, range, mccCode, isvNo); + } + + MchInfo mchInfo = mchInfoService.getById(mchNo); + + Map parentDefRate = null; + // 特约商户 + if(mchInfo.getType() == CS.MCH_TYPE_ISVSUB){ + + // 我的费率(商户上级服务商的费率) + result.put(RateConfig.READONLYPARENTAGENT, rateConfigService.queryPaywayFeeMap(mchInfo.getAgentNo() + "_" + RateConfig.AGENTRATE, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + // 默认费率 + parentDefRate = rateConfigService.queryPaywayFeeMap(mchInfo.getAgentNo() + "_" + RateConfig.MCHAPPLYDEF, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo); + result.put(RateConfig.READONLYPARENTDEFRATE, parentDefRate); + } + + // 商户费率为空时,将默认费率设置为商户费率 + if (ObjUtil.isEmpty(mchRateMap)) { + mchRateMap = parentDefRate; + } + + PaywayFee.resetData(mchRateMap, parentDefRate); + + result.put(RateConfig.MCHRATE, mchRateMap); + // 默认商户最大费率 + result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(getCurrentAgentNo() + "_" + RateConfig.MCHAPPLYMAX, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + return ApiRes.ok(result); + } + + // 配置子服务商的费率 + else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) ){ + Map result = new HashMap<>(); + + Map agentRate = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(infoId), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo); + // 查询已经配置的信息 + result.put(RateConfig.AGENTRATE, agentRate); + + AgentInfo agentInfo = agentInfoService.getById(infoId); + Map parentDefRate = null; + if (agentInfo.getPid() == null) { + parentDefRate = rateConfigService.queryPaywayFeeMap(infoId + "_" + RateConfig.AGENTDEF, CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo); + } + + if (parentDefRate == null) { + parentDefRate = rateConfigService.queryPaywayFeeMap(isvNo + "_" + RateConfig.AGENTDEF, CS.SYS_ROLE_TYPE.ISV, ifCode, range, mccCode, isvNo); + } + + Map mchFeeMax = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(infoId), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo); + Map isvMchFeeMax = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(isvNo), CS.SYS_ROLE_TYPE.ISV, ifCode, range, mccCode, isvNo); + + for (Map.Entry isvMchFeeMaxItem : isvMchFeeMax.entrySet()) { + String wayCode = isvMchFeeMaxItem.getKey(); + PaywayFee item = isvMchFeeMaxItem.getValue(); + if (mchFeeMax.get(wayCode) == null) { + // 为空传递空值 + mchFeeMax.put(wayCode, PaywayFee.toEmptyData(item)); + } + } + + result.put(RateConfig.MCHAPPLYMAX, mchFeeMax); + + // 我的费率(商户上级服务商的费率) + result.put(RateConfig.READONLYPARENTAGENT, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + // 默认费率 + result.put(RateConfig.READONLYPARENTDEFRATE, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgentDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + // 商户最大费率 + result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + PaywayFee.resetData(agentRate, baseConverter.newPaywayFeeMap(parentDefRate)); + + return ApiRes.ok(result); + + }// 配置服务商自己的配置 + else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode) ){ + Map result = new HashMap<>(); + + // 当前服务商的费率配置信息 + result.put(RateConfig.AGENTRATE, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgent(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + // 用于显示代理的费率信息(兼容前端) + result.put(RateConfig.READONLYPARENTAGENT, result.get(RateConfig.AGENTRATE)); + + // 商户默认费率 + result.put(RateConfig.MCHAPPLYDEF, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + // 服务商默认费率 + result.put(RateConfig.AGENTDEF, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByAgentDef(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + // 商户最大费率 + result.put(RateConfig.READONLYPARENTMCHMAX, rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchMax(getCurrentAgentNo()), CS.SYS_ROLE_TYPE.AGENT, ifCode, range, mccCode, isvNo)); + + return ApiRes.ok(result); + } + + return ApiRes.ok(); + } + + /** 保存费率信息 **/ + @MethodLog(remark = "配置费率") + @PostMapping(value="") + public ApiRes reset() { + + // 需要删除的集合, 比如: 配置渠道商底价, 关闭了某些渠道, 那么需要将下属的配置删除掉。 + List delList = new ArrayList<>(); + + String configMode = getValStringRequired("configMode"); + + // 主对象 + RateConfig mainRateConfig = getObject(RateConfig.class); + + mainRateConfig.setInfoType(commonGetInfoType(configMode)); // 必须设置infoType, 检查费率会使用 + + // 当前服务商的配置信息 + if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){ + mainRateConfig.setInfoId(getCurrentAgentNo()); + } + + List list = new ArrayList<>(); + + // 服务商默认费率 infoId = ISVNO_AGENTDEF infoType = 1(服务商) + if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.AGENTDEF))){ + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTDEF), PaywayFee.class) + .forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTDEF, configMode))); + } + + // 商户默认费率 infoId = ISVNO_MCHAPPLYDEF infoType = 1(服务商) + if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.MCHAPPLYDEF))){ + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHAPPLYDEF), PaywayFee.class) + .forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHAPPLYDEF, configMode))); + } + + // 商户费率 + if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.MCHRATE))){ + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHRATE), PaywayFee.class) + .forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHRATE, configMode))); + } + + // 服务商费率 + if(StringUtils.isNotEmpty(mainRateConfig.extv().getString(RateConfig.AGENTRATE))){ + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTRATE), PaywayFee.class) + .forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTRATE, configMode))); + + // 配置 服务商 需要删除 下属配置。 + delList = this.genDelRateConfigList(null, mainRateConfig.getInfoId(), mainRateConfig.getIfCode()); + } + + // 服务商最大费率 infoId = ISVNO_AGENTMAX infoType = 1(服务商) + if (!ObjUtil.isEmpty(mainRateConfig.extv().getString(RateConfig.AGENTMAX))) { + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.AGENTMAX), PaywayFee.class) + .forEach(r -> list.add( getFillInfoIdAndType(mainRateConfig, r, RateConfig.AGENTMAX, configMode))); + } + + // 商户最大费率 infoId = ISVNO_MCHAPPLYMAX infoType = 1(服务商) + if (configMode.equalsIgnoreCase(RateConfig.CONFIG_MODE_AGENTSELF) + || configMode.equalsIgnoreCase(RateConfig.CONFIG_MODE_AGENTEMCH)) { + // 配置代理费率和商户费率时,删除最大费率值 + mainRateConfig.getExt().remove(RateConfig.MCHAPPLYMAX); + } + + if (!ObjUtil.isEmpty(mainRateConfig.extv().getString(RateConfig.MCHAPPLYMAX))) { + JSON.parseArray(mainRateConfig.extv().getString(RateConfig.MCHAPPLYMAX), PaywayFee.class) + .forEach(r -> list.add(getFillInfoIdAndType(mainRateConfig, r, RateConfig.MCHAPPLYMAX, configMode))); + } + + LambdaQueryWrapper delWrapper = RateConfig.gw(); + delWrapper.eq(RateConfig::getIfCode, mainRateConfig.getIfCode()); + delWrapper.eq(RateConfig::getInfoType, commonGetInfoType(configMode)); + delWrapper.eq(mainRateConfig.getRange()!= null, RateConfig::getRange, mainRateConfig.getRange()); + delWrapper.eq(!ObjUtil.isEmpty(mainRateConfig.getMccCode()), RateConfig::getMccCode, mainRateConfig.getMccCode()); + delWrapper.in(RateConfig::getInfoId, commonGetInfoId(configMode, mainRateConfig.getInfoId())); + + rateConfigService.resetRate(list, delWrapper, mainRateConfig, false, delList); + return ApiRes.ok(); + } + + + private RateConfig getFillInfoIdAndType(RateConfig mainRateConfig, PaywayFee paywayFee, String infoSuffix, String configMode){ + + RateConfig result = new RateConfig(); + result.setInfoId(mainRateConfig.getInfoId() + "_" + infoSuffix); + result.setIfCode(mainRateConfig.getIfCode()); + result.setMccCode(mainRateConfig.getMccCode()); + result.setRange(mainRateConfig.getRange()); + result.setIsvNo(mainRateConfig.getIsvNo()); + result.setWayCode(paywayFee.getWayCode()); + result.setFeeType(paywayFee.getFeeType()); + result.setFeeRate(paywayFee.getFeeRate()); + result.setApplymentSupport(paywayFee.getApplymentSupport()); + result.setPaywayFeeDetail((JSONObject) JSON.toJSON(paywayFee)); + result.setInfoType(commonGetInfoType(configMode)); + + + return result; + } + + + + private String commonGetInfoType(String configMode){ + + //设置服务商信息 + if(RateConfig.CONFIG_MODE_MGRISV.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.ISV; + + }else if(RateConfig.CONFIG_MODE_MGRAGENT.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.AGENT; + + }else if(RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.MCH_APP; + + }else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.AGENT; + + }else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.AGENT; + + }else if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)){ + + return CS.SYS_ROLE_TYPE.MCH_APP; + + } + + return ""; + } + + private List commonGetInfoId(String configMode, String infoId){ + + //设置服务商信息 + if(RateConfig.CONFIG_MODE_MGRISV.equals(configMode)){ + + return Arrays.asList( + (infoId + "_" + RateConfig.ISVCOST), + (infoId + "_" + RateConfig.AGENTDEF), + (infoId + "_" + RateConfig.AGENTMAX), + (infoId + "_" + RateConfig.MCHAPPLYDEF), + (infoId + "_" + RateConfig.MCHAPPLYMAX) + ); + + }else if(RateConfig.CONFIG_MODE_MGRAGENT.equals(configMode)){ + + return Arrays.asList( + (infoId + "_" + RateConfig.AGENTRATE), + (infoId + "_" + RateConfig.AGENTDEF), + (infoId + "_" + RateConfig.AGENTMAX), + (infoId + "_" + RateConfig.MCHAPPLYDEF), + (infoId + "_" + RateConfig.MCHAPPLYMAX) + ); + + }else if(RateConfig.CONFIG_MODE_MGRMCH.equals(configMode)){ + + return Collections.singletonList( + (infoId + "_" + RateConfig.MCHRATE) + ); + + }else if(RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode)){ + + return Arrays.asList( + (infoId + "_" + RateConfig.AGENTDEF), + (infoId + "_" + RateConfig.MCHAPPLYDEF), + (infoId + "_" + RateConfig.MCHAPPLYMAX) + ); + + }else if(RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode)){ + + return Arrays.asList( + (infoId + "_" + RateConfig.AGENTRATE), + (infoId + "_" + RateConfig.MCHAPPLYMAX) + ); + + }else if(RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode)){ + + return Collections.singletonList( + (infoId + "_" + RateConfig.MCHRATE) + ); + + } + + return new ArrayList<>(); + } + + + /** + 获取待删除的列表集合 info_id/ info_type if_code way_code + + 以下三个场景需要判断: + 渠道商底价 + 运营平台 --》 设置服务商费率 + 服务商 配置 下级服务商费率 (服务商) + **/ + private List genDelRateConfigList(String isvNo, String agentNo, String ifCode){ + + String delPaywayCodeListStr = getValString("delPaywayCodeListStr"); + if(StringUtils.isEmpty(delPaywayCodeListStr)){ + return null; + } + + List delWayCodeList = JSON.parseArray(delPaywayCodeListStr, String.class); + + // 没有待删除的列表 + if(delWayCodeList.isEmpty()){ + return null; + } + + List result = new ArrayList<>(); + + + Set allAgentNoList = new HashSet<>(); + Set allMchNoList = new HashSet<>(); + Set allAppIdList = new HashSet<>(); + + + // 服务商不为空 + if(StringUtils.isNotEmpty(isvNo)){ + + + // 判断是否支持服务商 + if(SysConfigService.IS_HAS_AGENT_ENT){ + + // 查询所有的服务商列表 ( 一级服务商 ) + agentInfoService.list(AgentInfo.gw().select(AgentInfo::getAgentNo).eq(AgentInfo::getIsvNo, isvNo)).forEach(r -> allAgentNoList.add(r.getAgentNo())); + + } + + // 查询所有的商户列表 [ 无需查询服务商的所属了, 已经是全部服务商下的商户了。 ] + mchInfoService.lambdaQuery().select(MchInfo::getMchNo).list().forEach(r -> allMchNoList.add(r.getMchNo())); + + // 查询下级服务商的 子服务商【递归】 + for (String agentNoItem : allAgentNoList) { + allAgentNoList.addAll(agentInfoService.queryAllSubAgentNo(agentNoItem)); + } + + // 查询下级服务商【递归】的商户 + + } + + // 服务商不为空 + if(StringUtils.isNotEmpty(agentNo)){ + + // 查询所有的服务商列表 ( 当前服务商的 直属 服务商 ) + agentInfoService.lambdaQuery().select(AgentInfo::getAgentNo).eq(AgentInfo::getPid, agentNo).list().forEach(r -> allAgentNoList.add(r.getAgentNo())); + + // 查询所有的商户列表 ( 当前服务商的 直属 商户 ) 【 当前服务商的所属商户 】 + mchInfoService.lambdaQuery().select(MchInfo::getMchNo).eq(MchInfo::getAgentNo, agentNo).list().forEach(r -> allMchNoList.add(r.getMchNo())); + + // 查询下级服务商的 子服务商【递归】 + for (String agentNoItem : allAgentNoList) { + allAgentNoList.addAll(agentInfoService.queryAllSubAgentNo(agentNoItem)); + } + + // 查询下级服务商 所属的商户集合 + for (String agentNoItem : allAgentNoList) { + mchInfoService.lambdaQuery().select(MchInfo::getMchNo).eq(MchInfo::getAgentNo, agentNoItem) + .list().forEach(r -> allMchNoList.add(r.getMchNo())); + } + + } + + if(!allMchNoList.isEmpty()){ + + // 查询所有的商户列表 + mchAppService.lambdaQuery().select(MchAppEntity::getMchNo).in(MchAppEntity::getMchNo, allMchNoList) + .list().forEach(r -> allAppIdList.add(r.getAppId())); + } + + + // 服务商: 包括 服务商配置, 下级服务商默认、 服务商商户默认 + for (String agentNoItem : allAgentNoList) { + for (String wayCode : delWayCodeList) { + + RateConfig r = new RateConfig(); + r.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.AGENTRATE)); r.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r.setIfCode(ifCode); r.setWayCode(wayCode); + result.add(r); + + RateConfig r1 = new RateConfig(); + r1.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.AGENTDEF)); r1.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r1.setIfCode(ifCode); r1.setWayCode(wayCode); + result.add(r1); + + RateConfig r2 = new RateConfig(); + r2.setInfoId(RateConfig.buildInfoId(agentNoItem, RateConfig.MCHAPPLYDEF)); r2.setInfoType(CS.SYS_ROLE_TYPE.AGENT); r2.setIfCode(ifCode); r2.setWayCode(wayCode); + result.add(r2); + } + } + + + // 商户: 包括 商户应用费率 + for (String appIdItem : allAppIdList) { + for (String wayCode : delWayCodeList) { + + RateConfig r = new RateConfig(); + r.setInfoId(RateConfig.buildInfoId(appIdItem, RateConfig.MCHRATE)); r.setInfoType(CS.SYS_ROLE_TYPE.MCH_APP); r.setIfCode(ifCode); r.setWayCode(wayCode); + result.add(r); + } + } + + return result; + } + + @GetMapping("/rateInfoDetail") + public ApiRes rateInfoDetail() { + String isvNo = getValStringRequired("isvNo"); + String ifCode = getValStringRequired("ifCode"); + Integer range = getValInteger("range"); + String mccCode = getValString("mccCode"); + String infoType = getValStringRequired("infoType"); + String infoId = getValStringRequired("infoId"); + + String currentAgentNo = getCurrentAgentNo(); + + List result = rateConfigV2Service.getRankFeeList(isvNo, infoType, infoId, ifCode, range, mccCode, currentAgentNo); + + return ApiRes.ok(result); + } + + @PostMapping("/resetV2") + public ApiRes resetV2() { + String currentAgentNo = getCurrentAgentNo(); + + RateConfigSimple rateConfigSimple = getObject(RateConfigSimple.class); + + if (rateConfigSimple.getInfoType().equalsIgnoreCase(CS.SYS_ROLE_TYPE.AGENT)) { + AgentInfo agentInfo = agentInfoService.getById(rateConfigSimple.getInfoId()); + Assert.equals(agentInfo.getPid(), currentAgentNo, "所操作的服务商与登录账号非上下级关系"); + } else if (rateConfigSimple.getInfoType().equalsIgnoreCase(CS.SYS_ROLE_TYPE.MCH)) { + MchInfo mchInfo = mchInfoService.getById(rateConfigSimple.getInfoId()); + Assert.equals(mchInfo.getAgentNo(), currentAgentNo, "所操作的用户与登录账号非上下级关系"); + } else { + throw new BizException("未知的操作类型"); + } + + rateConfigV2Service.save(rateConfigSimple); + + return ApiRes.ok(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/product/ProductController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/product/ProductController.java new file mode 100644 index 0000000..35e612e --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/product/ProductController.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.agent.ctrl.product; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.PackageOrder; +import com.jeequan.jeepay.db.entity.ProductInfo; +import com.jeequan.jeepay.db.entity.ProductType; +import com.jeequan.jeepay.service.impl.ProductAppService; +import com.jeequan.jeepay.service.impl.ProductInfoService; +import com.jeequan.jeepay.service.impl.ProductTypeService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 产品中心 + * + * @author deng + * @since 2024-04-10 + */ +@RestController +@RequestMapping("/api/product") +public class ProductController extends CommonCtrl { + + @Autowired + private ProductInfoService productInfoService; + @Autowired + private ProductTypeService productTypeService; + @Autowired + private ProductAppService productAppService; + + /** + * 产品中心列表 + **/ + @RequestMapping(value = "/getProductList", method = RequestMethod.GET) + @MethodLog(remark = "产品中心列表") + public ApiRes getProductList() throws BizException { + ProductInfo productInfo = getObject(ProductInfo.class); + /*LambdaQueryWrapper wrapper = ProductInfo.gw(); + selectParams(productInfo, wrapper); + wrapper.orderByDesc(ProductInfo::getCreatedAt);*/ + Page page = new Page<>(); + List productInfoList = productInfoService.getProductList(productInfo.getProductName(), productInfo.getState(), productInfo.getProductType()); + page.setRecords(productInfoList); + page.setTotal(productInfoList.size()); + page.setCurrent(1); + return ApiRes.ok(page); + } + + @RequestMapping(value = "/getProductById", method = RequestMethod.GET) + @MethodLog(remark = "产品详情") + public ApiRes getProductById() throws BizException { + //获取查询条件 + ProductInfo productInfo = getObject(ProductInfo.class); + + ProductInfo info = productInfoService.getProductById(productInfo.getProductId()); + return ApiRes.ok(info); + } + + @RequestMapping(value = "/getProductByUser", method = RequestMethod.GET) + @MethodLog(remark = "被选择用户绑定关系") + public ApiRes getProductByUser() throws BizException { + //获取查询条件 + String productOrPackage = getValStringRequired("productOrPackage"); + String userNo = getValStringRequired("userNo"); + + ProductInfo resut=new ProductInfo(); + //查询已关联已开通的应用数量, + List packageOrderList = productAppService.getList(productOrPackage,userNo); + List bindingApp = packageOrderList.stream().map(PackageOrder::getAppId).filter(str-> !str.isEmpty()).distinct().collect(Collectors.toList()); + resut.setApplyCount(packageOrderList.size()); + resut.setBindingAppList(bindingApp); + //返回收费信息和剩余天数以及总剩余天数 + List packageOrderListSave =new ArrayList<>(); + long allRemainingDays = 0L; + for (PackageOrder packageOrder : packageOrderList) { + if (packageOrder.getCostRule() != null){ + JSONArray costRule = packageOrder.getCostRule(); + //目前规则只能选取一条 + int validTime = costRule.getJSONObject(0).getIntValue("validTime"); + if (costRule.getJSONObject(0).getDate("autoTime") != null){ + LocalDate currentDate = costRule.getJSONObject(0).getDate("autoTime").toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + // 计算到期后的日期 + LocalDate futureDate = currentDate.plusDays(validTime); + // 计算剩余天数 + LocalDate today = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + long remainingDays = ChronoUnit.DAYS.between(today, futureDate); + packageOrder.setRemainingDays(remainingDays); + //暂时不需要 + //productAppListSave.add(productApp); + allRemainingDays += remainingDays; + } + } + } + //暂时不需要 + //info.setProductAppList(productAppListSave); + resut.setAllRemainingDays(allRemainingDays); + + return ApiRes.ok(resut); + } + + @RequestMapping(value = "/startProduct", method = RequestMethod.POST) + @MethodLog(remark = "产品开通") + public ApiRes startProduct() throws BizException { + //获取查询条件 + PackageOrder app = getObject(PackageOrder.class); + Assert.isTrue(!ObjUtil.isEmpty(getValString("userNo")), "用户号[userNo]不能为空"); + app.setMchNo(getValString("userNo")); + app.setCreatedAt(new Date()); + app.setUpdatedAt(new Date()); + app.setCreatedUid(getCurrentUser().getSysUserId()); + productInfoService.startProduct(app); + return ApiRes.ok("已提交!"); + } + + @RequestMapping(value = "/getProductTypeList", method = RequestMethod.GET) + @MethodLog(remark = "获取所有分类列表") + public ApiRes getProductTypeList() throws BizException { + return ApiRes.ok(productTypeService.list(ProductType.gw())); + } + + /** + * @author: huay + * @describe: 查询公共条件 + */ + public void selectParams(ProductInfo productInfo, LambdaQueryWrapper wrapper) { + wrapper.like(StringUtils.isNotEmpty(productInfo.getProductName()), ProductInfo::getProductName, productInfo.getProductName()); + wrapper.eq(ProductInfo::getState, productInfo.getState()); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrCodeController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrCodeController.java new file mode 100644 index 0000000..a1ab201 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrCodeController.java @@ -0,0 +1,482 @@ +package com.jeequan.jeepay.agent.ctrl.qrcode; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.qrshell.AbstractGenerator; +import com.jeequan.jeepay.bizcommons.manage.qrshell.ShellQRGenerator; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.export.MchQrCodesExportExcel; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 商户应用管理类 + * + * @author zhuxiao + * @date 2021-06-16 09:15 + */ +@RestController +@RequestMapping("/api/mchQrCodes") +public class MchQrCodeController extends CommonCtrl { + + @Autowired private MchQrcodeCardService mchQrcodeCardService; + @Autowired private MchQrcShellService mchQrcShellService; + @Autowired private MchInfoService mchInfoService; + @Autowired private MchStoreService mchStoreService; + @Autowired private MchAppService mchAppService; + @Autowired private MchApplymentService mchApplymentService; + + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_LIST')") + @GetMapping + public ApiRes list() { + + // 构造查询条件 + MchQrcodeCard mchQrCode = getObject(MchQrcodeCard.class); + + // 可查看自己和全部下级代理的设备 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + // 自己和下级服务商 + if (CollUtil.isNotEmpty(subAgentNoList)){ + mchQrCode.setSubAgentNoList(subAgentNoList); + } + IPage page = mchQrcodeCardService.selectPageRecords(getIPage(), mchQrCode); + if (page.getTotal() == 0) { + return ApiRes.page(page); + } + + // 列表添加是否属于自身,设备只能绑定直属商户,app端展示隐藏也使用此字段 + for (MchQrcodeCard qrcodeCard: page.getRecords()) { + if (currentAgentNo.equals(qrcodeCard.getAgentNo())) { + qrcodeCard.addExt("isSelf", true); + } + } + + return ApiRes.page(page); + } + + + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_VIEW')") + @GetMapping("/{recordId}") + public ApiRes detail(@PathVariable("recordId") Long recordId) { + + // 可查看自己和全部下级代理的码牌 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId); + if (!subAgentNoList.contains(dbRecord.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 设备是否属于自身 + if (getCurrentAgentNo().equals(dbRecord.getAgentNo())) { + dbRecord.addExt("isSelf", true); + } + + // 添加服务商、商户、门店、应用名称 + AgentInfo allotAgent = agentInfoService.getById(dbRecord.getAgentNo()); + if (allotAgent != null) { + dbRecord.addExt("agentName", allotAgent.getAgentName()); + } + if (dbRecord.getBindState() == CS.YES) { + if (StringUtils.isNotBlank(dbRecord.getMchNo())) { + MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo()); + if (mchInfo != null) { + dbRecord.addExt("mchName", mchInfo.getMchName()); + } + } + + if (dbRecord.getStoreId() != null) { + MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId()); + if (mchStore != null) { + dbRecord.addExt("storeName", mchStore.getStoreName()); + } + } + + if (StringUtils.isNotBlank(dbRecord.getAppId())) { + MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId()); + if (mchAppEntity != null) { + dbRecord.addExt("appName", mchAppEntity.getAppName()); + } + } + } + MchApplyment mchApplyment = mchApplymentService.getById(dbRecord.getMchApplyId()); + // 封装URL + dbRecord.addExt("qrUrl", sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, dbRecord.getEntryPage(), recordId + "", mchApplyment.getIsvNo())); + return ApiRes.ok(dbRecord); + } + + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')") + @MethodLog(remark = "更新二维码信息") + @PutMapping("/{recordId}") + public ApiRes update(@PathVariable("recordId") Long recordId) { + + // 可查看自己和全部下级代理的码牌 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId); + if (!subAgentNoList.contains(dbRecord.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 处理金额类型 + handleParamAmount("fixedPayAmount"); + + MchQrcodeCard mchQrCode = getObject(MchQrcodeCard.class); + mchQrCode.setBatchId(null); // 批次号不允许变更 + mchQrCode.setCreatedAt(null); + mchQrCode.setUpdatedAt(null); + mchQrCode.setQrcId(recordId); + + // 解绑同时设置商户号为空串,设置门店ID为-1 + if (mchQrCode.getBindState() != null && mchQrCode.getBindState() == CS.NO) { + mchQrCode.setMchNo(""); + mchQrCode.setAppId(""); + mchQrCode.setStoreId("-1"); + } + + boolean result = mchQrcodeCardService.updateById(mchQrCode); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + return ApiRes.ok(); + } + + + + /** 解析二维码 && 验证二维码是否可绑定 **/ + @GetMapping("/parseQrCodeUrl") + public ApiRes parseQrCodeUrl() { + + String url = getValStringRequired("qrUrl"); + + // 不是支付平台开头的, 说明不是可用二维码 + if(!url.startsWith(sysConfigService.getDBApplicationConfig().getPaySiteUrl())){ + throw new BizException("二维码解析失败"); + } + + int tokenIndex = url.indexOf(JeepayKit.TOKEN_KEY + "="); + if(tokenIndex <= 0){ + throw new BizException("二维码解析失败"); + } + + String token = url.substring(tokenIndex + 12); + + QRCodeParams qrCodeParams = JSON.parseObject(JeepayKit.aesDecode(token), QRCodeParams.class); //解析token + + MchQrcodeCard mchQrcodeCard = mchQrcodeCardService.getById( qrCodeParams.getId()); + + // 不存在 不可用 已绑定 + if(mchQrcodeCard == null || mchQrcodeCard.getQrcState() != CS.YES || mchQrcodeCard.getBindState() != CS.NO){ + throw new BizException("二维码不存在"); + } + + return ApiRes.ok(mchQrcodeCard.getQrcId()); + } + + /** + * @author: xiaoyu + * @date: 2022/1/14 9:45 + * @describe: 订单列表数据导出 + */ + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EXPORT')") + @RequestMapping(value="/exportExcel", method = RequestMethod.GET) + public void exportExcel() throws Exception{ + + String exportModel = getValStringRequired("exportModel"); + MchQrcodeCard mchQrcodeCard = getObject(MchQrcodeCard.class); + LambdaQueryWrapper wrapper = MchQrcodeCard.gw(); + + if(mchQrcodeCardService.countByWrapper(mchQrcodeCard) > 500){ + throw new BizException("导出数量不可超过500"); + } + + // 服务商号条件不为空,搜索该服务商号下 + wrapper.eq(StringUtils.isNotEmpty(mchQrcodeCard.getAgentNo()), MchQrcodeCard::getAgentNo, mchQrcodeCard.getAgentNo()); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + // 自己和下级服务商 + wrapper.in(CollUtil.isNotEmpty(subAgentNoList), MchQrcodeCard::getAgentNo, subAgentNoList); + IPage pages = mchQrcodeCardService.listByPage(getIPage(true), mchQrcodeCard, wrapper); + + // 查询当前系统配置信息 + DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig(); + + // Excel: 信息和url + if ("infoAndUrl".equals(exportModel)) { + try { + List newList = new LinkedList<>(); + for (MchQrcodeCard qrcodeCard:pages.getRecords()) { + MchApplyment mchApplyment = mchApplymentService.getById(qrcodeCard.getMchApplyId()); + JSONObject object = (JSONObject) JSONObject.toJSON(qrcodeCard); + object.put("fixedPayAmount", AmountUtil.convertCent2Dollar(qrcodeCard.getFixedPayAmount())); + object.put("qrCodeUrl", dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, qrcodeCard.getEntryPage(), qrcodeCard.getQrcId() + "", mchApplyment.getIsvNo())); + newList.add(object); + } + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), MchQrCodesExportExcel.class); + // excel输出 + ExcelUtil.exportExcel(linkedList, "码牌", "码牌", MchQrCodesExportExcel.class, "码牌", response); + }catch (Exception e) { + logger.error("导出excel失败", e); + throw new BizException("导出二维码失败!"); + } + + // 模板图片 || 纯二维码 || 二维码包含ID + }else if ("templateImg".equals(exportModel) || "qrcode".equals(exportModel) || "qrcodeAndQrcId".equals(exportModel) ) { + + //文件的名称 + String downloadFilename = "qrcode_" + DateUtil.today() + ".zip"; + //设置格式 + response.setCharacterEncoding("UTF-8"); + response.setHeader("content-Type", "application/x-msdownload"); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadFilename, "UTF-8")); + + ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()); + + // 查询所有的模板数据 + Map map = new HashMap<>(); + pages.getRecords().stream().forEach(r -> map.put(r.getQrcShellId(), null)); + if(!map.keySet().isEmpty()){ + mchQrcShellService.list(MchQrcShell.gw().in(MchQrcShell::getSid, map.keySet())).stream().forEach(r -> { + map.put(r.getSid(), r); + }); + } + + for (MchQrcodeCard qrcodeCard:pages.getRecords()) { + + String mchStoreName = ""; + if(qrcodeCard.getBindState() == CS.YES && qrcodeCard.getStoreId() != null && !"-1".equals(qrcodeCard.getStoreId())){ + MchStore mchStore = mchStoreService.getById(qrcodeCard.getStoreId()); + mchStoreName = mchStore != null ? mchStore.getStoreName() : ""; + } + + BufferedImage bufferedImage = null; + + MchQrcShell mchQrcShell = map.get(qrcodeCard.getQrcShellId()); + + AbstractGenerator abstractGenerator = SpringBeansUtil.getBean(ShellQRGenerator.class); + if(mchQrcShell != null && "templateImg".equals(exportModel)){ //存在模板 && 显式导出模板 + abstractGenerator = getAbstractGenerator(mchQrcShell.getStyleCode()); + } + + String configStr = null; + if("templateImg".equals(exportModel)){ // 模板图片 + if(mchQrcShell != null){ + configStr = mchQrcShell.getConfigInfo(); + } + }else if("qrcode".equals(exportModel)){ // 纯二维码(不包含ID) + + configStr = "{showIdFlag: false}"; + + }else if("qrcodeAndQrcId".equals(exportModel)){ // 二维码 + ID + + configStr = "{showIdFlag: true}"; + } + + MchApplyment applyment = mchApplymentService.getById(qrcodeCard.getMchApplyId()); + + bufferedImage = abstractGenerator + .genQrImgBuffer(configStr, + dbApplicationConfig.genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, qrcodeCard.getEntryPage(), qrcodeCard.getQrcId() + "", applyment.getIsvNo()), + qrcodeCard.getQrcId(), + mchStoreName, + false + ); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ImageIO.write(bufferedImage, "png", out); + InputStream is = new ByteArrayInputStream(out.toByteArray()); + zos.putNextEntry(new ZipEntry( qrcodeCard.getQrcId() + ".png")); + byte[] buffer = new byte[1024]; + int r = 0; + while ((r = is.read(buffer)) != -1) { + zos.write(buffer, 0, r); + } + is.close(); + is = null; + out.close(); + out = null; + zos.flush(); + } + + zos.flush(); + zos.close(); + + } + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 绑定码牌 + */ + @MethodLog(remark = "绑定码牌") + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')") + @PutMapping("/bind/{recordId}") + public ApiRes bind(@PathVariable("recordId") Long recordId) { + + String mchNo = getValStringRequired("mchNo"); + String appId = getValStringRequired("appId"); + String storeId = getValStringRequired("storeId"); + + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("商户不存在"); + } + + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(recordId); + if (dbRecord == null || StringUtils.isBlank(dbRecord.getAgentNo()) || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + MchQrcodeCard updateRecord = new MchQrcodeCard(); + updateRecord.setQrcId(recordId).setMchNo(mchNo).setStoreId(storeId).setAppId(appId).setBindState(CS.YES); + + mchQrcodeCardService.bindEmptyQR(updateRecord); + + return ApiRes.ok(); + } + + /** + * @Author: zx + * @Description: 解绑码牌 + * @Date: 15:59 2022/5/30 + */ + @MethodLog(remark = "解绑码牌") + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_RELIEVE')") + @PostMapping("/unbind/{qrcId}") + public ApiRes unbind(@PathVariable("qrcId") Long qrcId) { + + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId); + if (dbRecord == null || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.customFail("解绑失败"); + } + + mchQrcodeCardService.unbind(dbRecord); + + return ApiRes.ok(); + } + + /** + * @Author: zx + * @Description: 查看码牌绑定的设备列表 + * @Date: 15:59 2022/5/30 + */ + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_EDIT')") + @GetMapping("/bindDevice/{qrcId}") + public ApiRes bindDevice(@PathVariable("qrcId") Long qrcId) { + + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId); + if (dbRecord == null || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + IPage page = mchQrcodeCardService.getBindDevice(getIPage(), dbRecord, getCurrentAgentNo()); + + return ApiRes.page(page); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 划拨码牌给服务商 + */ + @MethodLog(remark = "划拨/收回码牌给服务商") + @PreAuthorize("hasAuthority('ENT_DEVICE_QRC_ALLOT')") + @PostMapping("/allotQrc") + public ApiRes allotQrc() { + + // 服务商是否支持划拨码牌、设备 + SysConfig isSupportAgentAllot = sysConfigService.getById("isSupportAgentAllot"); + if(isSupportAgentAllot == null || String.valueOf(CS.NO).equals(isSupportAgentAllot.getConfigVal())){ + throw new BizException("不支持服务商划拨码牌、设备"); + } + + String allotType = getValStringRequired("allotType"); // 划拨类型:select-勾选划拨 batch-批次划拨 + String allotOrRecover = getValStringRequired("allotOrRecover"); // 分配类型:allot-划拨 recover-收回 + + List qrcIdList = new LinkedList<>(); + + // 构建批量更新设备ID集合 + if (allotType.equals("select")) { + + String allotds = getValStringRequired("allotIds"); + qrcIdList = Arrays.stream(allotds.split(",")).map(Long::parseLong).collect(Collectors.toList()); + + }else if (allotType.equals("batch")) { + + String batchId = getValStringRequired("batchId"); + List list = mchQrcodeCardService.list(MchQrcodeCard.gw().eq(MchQrcodeCard::getBatchId, batchId)); + if (CollUtil.isEmpty(list)) { + throw new BizException("批次号错误"); + } + for (MchQrcodeCard mchQrcodeCard : list) { + qrcIdList.add(mchQrcodeCard.getQrcId()); + } + + }else { + throw new BizException("划拨类型错误"); + } + + if (CollUtil.isEmpty(qrcIdList)) { + throw new BizException("请选择码牌"); + } + + // 只能操作下级代理 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + + // 1、收回码牌 + if (allotOrRecover.equals("recover")) { + mchQrcodeCardService.recoverQrc(true, qrcIdList, subAgentNoList, getCurrentAgentNo()); + return ApiRes.ok(); + } + + // 2、划拨码牌 + String agentNo = getValStringRequired("agentNo"); + List mchNoList = getMchNoListByAgentNo(agentNo); + + mchQrcodeCardService.allotQrc(true, agentNo, qrcIdList, mchNoList, subAgentNoList); + + return ApiRes.ok(); + } + + private AbstractGenerator getAbstractGenerator(String code){ + + AbstractGenerator generator = SpringBeansUtil.getBean(code + "Generator", AbstractGenerator.class); + if(generator == null){ + throw new BizException("选择模板[" + code + "]不存在!"); + } + return generator; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrcShellController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrcShellController.java new file mode 100644 index 0000000..579d405 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/qrcode/MchQrcShellController.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.agent.ctrl.qrcode; + +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.qrshell.AbstractGenerator; +import com.jeequan.jeepay.bizcommons.manage.qrshell.ShellQRGenerator; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchQrcShell; +import com.jeequan.jeepay.db.entity.MchQrcodeCard; +import com.jeequan.jeepay.db.entity.MchStore; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchQrcShellService; +import com.jeequan.jeepay.service.impl.MchQrcodeCardService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.awt.image.BufferedImage; + + +/** + * 二维码模板管理 + * + * @author terrfly + * @date 2022/1/17 14:22 + */ +@RestController +@RequestMapping("/api/mchQrcShells") +public class MchQrcShellController extends CommonCtrl { + + @Autowired private MchQrcodeCardService mchQrcodeCardService; + @Autowired private MchQrcShellService mchQrcShellService; + @Autowired private SysConfigService sysConfigService; + @Autowired private MchApplymentService mchApplymentService; + + /** 根据qrcId获取图片base64 **/ + @GetMapping("/viewByQrc/{qrcId}") + public ApiRes viewByQrc(@PathVariable("qrcId") Long qrcId) throws Exception { + + MchQrcodeCard dbRecord = mchQrcodeCardService.getById(qrcId); + + String mchStoreName = ""; + if(dbRecord.getBindState() == CS.YES && dbRecord.getStoreId() != null && !"-1".equals(dbRecord.getStoreId())){ + MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId()); + mchStoreName = mchStore != null ? mchStore.getStoreName() : ""; + } + + AbstractGenerator shellGenerator = SpringBeansUtil.getBean(ShellQRGenerator.class); + + MchApplyment applyment = mchApplymentService.getById(dbRecord.getMchApplyId()); + + // 封装URL + String qrUrlContent = sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC, dbRecord.getEntryPage(), qrcId + "", applyment.getIsvNo()); + + if(dbRecord.getQrcShellId() == null || dbRecord.getQrcShellId() <= 0){ + //给前端拼接上 【 data:image/jpg;base64 】 + return ApiRes.ok("data:image/jpg;base64,"+ AbstractGenerator.convertImgBase64(shellGenerator.genQrImgBuffer(null, qrUrlContent, qrcId, mchStoreName, false))); + } + + MchQrcShell mchQrcShell = mchQrcShellService.getById(dbRecord.getQrcShellId()); + + BufferedImage bufferedImage = getAbstractGenerator(mchQrcShell.getStyleCode()).genQrImgBuffer(mchQrcShell.getConfigInfo(), qrUrlContent, qrcId, mchStoreName, false); + + //给前端拼接上 【 data:image/jpg;base64 】 + return ApiRes.ok("data:image/jpg;base64,"+ AbstractGenerator.convertImgBase64(bufferedImage)); + } + + + private AbstractGenerator getAbstractGenerator(String code){ + + AbstractGenerator generator = SpringBeansUtil.getBean(code + "Generator", AbstractGenerator.class); + if(generator == null){ + throw new BizException("选择模板[" + code + "]不存在!"); + } + return generator; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/settle/SettleInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/settle/SettleInfoController.java new file mode 100644 index 0000000..20eaaaf --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/settle/SettleInfoController.java @@ -0,0 +1,130 @@ +package com.jeequan.jeepay.agent.ctrl.settle; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.export.SettleInfoExportExcel; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.service.impl.PayInterfaceDefineService; +import com.jeequan.jeepay.service.impl.SettleInfoService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +/** + * TODO + * + * @author crystal + * @date 2023/12/6 15:11 + */ +@RestController +@RequestMapping("/api/settle") +public class SettleInfoController extends CommonCtrl { + + @Autowired private SettleInfoService settleInfoService; + @Autowired private PayInterfaceDefineService payInterfaceDefineService; + + @PreAuthorize("hasAuthority('ENT_SETTLE_LIST')") + @GetMapping + public ApiRes list() { + SettleInfo info = getObject(SettleInfo.class); + JSONObject paramJSON = getReqParamJSON(); + LambdaQueryWrapper wrapper = SettleInfo.gw(); + // 查询下级服务商 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + wrapper.in(SettleInfo::getAgentNo,subAgentNoList); + //wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo()); + Page pages = settleInfoService.pageList(getIPage(), wrapper,info,paramJSON); + Map ifCodeMap = new HashMap<>(); + List list = payInterfaceDefineService.list(); + if(!list.isEmpty()){ + for (PayInterfaceDefine define:list) { + ifCodeMap.put(define.getIfCode(), define.getIfName()); + } + } + for (SettleInfo data:pages.getRecords()) { + if(StringUtils.isNotBlank(data.getIfCode())){ + data.setIfName(ifCodeMap.get(data.getIfCode())); + } + } + return ApiRes.page(pages); + } + + /** + * 结算信息导出 + */ + @RequestMapping(value="/exportExcel", method = RequestMethod.GET) + public void exportExcel() { + try { + SettleInfo info = getObject(SettleInfo.class); + JSONObject paramJSON = getReqParamJSON(); + LambdaQueryWrapper wrapper = SettleInfo.gw(info); + wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo()); + Page pages = settleInfoService.pageList(getIPage(), wrapper,info,paramJSON); + Map ifCodeMap = new HashMap<>(); + List list = payInterfaceDefineService.list(); + if(!list.isEmpty()){ + for (PayInterfaceDefine define:list) { + ifCodeMap.put(define.getIfCode(), define.getIfName()); + } + } + List newList = new LinkedList<>(); + + if (!pages.getRecords().isEmpty()){ + //成功交易总笔数 + List infoList = pages.getRecords().stream().filter(p -> p.getState() == 2).collect(Collectors.toList()); + //成功交易总金额 + BigDecimal allSuccessAmount = BigDecimal.ZERO; + for (SettleInfo settleInfo : infoList) { + allSuccessAmount=allSuccessAmount.add(BigDecimal.valueOf(settleInfo.getSettleAmt())); + } + + for (SettleInfo data:pages.getRecords()) { + if(StringUtils.isNotBlank(data.getIfCode())){ + data.setIfName(ifCodeMap.get(data.getIfCode())); + } + JSONObject object = (JSONObject) JSONObject.toJSON(data); + newList.add(object); + } + } + + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), SettleInfoExportExcel.class); + // excel输出 + ExcelUtil.exportExcel(linkedList, "结算信息", "结算信息", SettleInfoExportExcel.class, "结算信息", response); + }catch (Exception e){ + logger.error("导出excel失败", e); + throw new BizException("导出结算信息失败!"); + } + } + + @GetMapping("/count") + public ApiRes getCount(){ + SettleInfo info = getObject(SettleInfo.class); + LambdaQueryWrapper wrapper = SettleInfo.gw(); + // 时间范围条件 + Date[] dateRange = info.buildQueryDateRange(); + if (dateRange[0] != null) { + wrapper.ge(SettleInfo::getUpdatedAt, dateRange[0]); + } + if (dateRange[1] != null) { + wrapper.le(SettleInfo::getUpdatedAt, dateRange[1]); + } + wrapper.eq(SettleInfo::getAgentNo, getCurrentAgentNo()); + List infoList = settleInfoService.list(wrapper); + return settleInfoService.getCount(infoList); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/ExportExcelStatisticController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/ExportExcelStatisticController.java new file mode 100644 index 0000000..67c4c0a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/ExportExcelStatisticController.java @@ -0,0 +1,175 @@ +package com.jeequan.jeepay.agent.ctrl.statistics; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrderCount; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.export.statistic.*; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.PayOrder; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.StatsDeviceService; +import com.jeequan.jeepay.service.impl.StatsPayWayService; +import com.jeequan.jeepay.service.impl.StatsTradeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.formula.functions.T; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.math.BigDecimal; +import java.util.LinkedList; +import java.util.List; + +/** + * 统计列表接口 + * + * @author xiaoyu + * + * @date 2022/5/23 16:52 + */ +@Slf4j +@RestController +@RequestMapping("/api/statistic/export") +public class ExportExcelStatisticController extends CommonCtrl { + + @Autowired private AgentInfoService agentInfoService; + @Autowired private StatsTradeService statsTradeService; + @Autowired private StatsPayWayService statsPayWayService; + @Autowired private StatsDeviceService statsDeviceService; + + /** + * @author: xiaoyu + * @date: 2022/5/23 17:15 + * @describe: 统计列表 + */ + @PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')") + @RequestMapping(value="", method = RequestMethod.GET) + public void list() { + JSONObject paramJSON = getReqParamJSON(); + PayOrder payOrder = getObject(PayOrder.class); + + List agentSubList = null; + + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + // 查询服务商所有下级 + agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + } + String method = getValStringRequired("method"); + String mchNo = null; + Page countPage = null; + switch (method) { + case CS.STATISTIC_TYPE.MCH: + // 商户 + countPage = statsTradeService.selectMchStatsList(paramJSON, agentSubList); + exportExcel(countPage, StatisticMchExportExcel.class, "商户统计"); + break; + case CS.STATISTIC_TYPE.AGENT: + // 服务商 + countPage = statsTradeService.selectAgentStatsList(paramJSON, agentSubList); + exportExcel(countPage, StatisticAgentExportExcel.class, "服务商统计"); + break; + case CS.STATISTIC_TYPE.TRANSACTION: + // 交易报表 + // mapPage = payOrderService.countListByTransaction(payOrder, paramJSON, agentSubList); + countPage = statsTradeService.selectTransactionStatsList(payOrder, paramJSON, agentSubList); + exportExcel(countPage, StatisticTransactionExportExcel.class, "交易报表"); + break; + case CS.STATISTIC_TYPE.STORE: + // 门店 + getValStringRequired("mchNo"); + countPage = statsTradeService.selectStoreStatsList(paramJSON); + exportExcel(countPage, StatisticStoreExportExcel.class, "门店统计"); + break; + case CS.STATISTIC_TYPE.WAY_CODE: + // 支付方式 + getValStringRequired("mchNo"); + countPage = statsPayWayService.selectPayWayStatsList(paramJSON); + exportExcel(countPage, StatisticWayCodeExportExcel.class, "支付方式统计"); + break; + case CS.STATISTIC_TYPE.WAY_CODE_TYPE: + // 支付类型 + getValStringRequired("mchNo"); + countPage = statsPayWayService.selectWayCodeTypeStatsList(paramJSON); + exportExcel(countPage, StatisticWayCodeTypeExportExcel.class, "支付类型统计"); + break; + case CS.STATISTIC_TYPE.DEVICE: + // 设备统计 + countPage = statsDeviceService.selectStatsList(paramJSON, agentSubList); + exportExcel(countPage, StatisticDeviceExportExcel.class, "设备统计"); + break; + default: + break; + } + } + + public List getAgentSubList(JSONObject paramJSON, PayOrder payOrder) { + List allAgentNoList = null; + if (StringUtils.isNotEmpty(payOrder.getAgentNo())) { + Boolean onlyOne = paramJSON.getBoolean("onlyOne"); +// if (onlyOne) { +// // 仅查询单个服务商 +// allAgentNoList = Arrays.asList(payOrder.getAgentNo()); +// } else if ("onlyOne".equals(payOrder.getAgentNo())) { +// allAgentNoList = Arrays.asList(getCurrentAgentNo()); +// } else { +// // 查询服务商所有下级 +// allAgentNoList = agentInfoService.queryAllSubAgentNo(payOrder.getAgentNo()); +// } + } + return allAgentNoList; + } + + /** 通用导出类 **/ + public void exportExcel(Page countPage, Class clazz, String title) { + try { + + List newList = new LinkedList<>(); + countPage.getRecords().stream().forEach(record -> { + JSONObject itemData = (JSONObject) JSONObject.toJSON(record); + // 交易金额转换 + BigDecimal totalSuccAmt = new BigDecimal(record.getTotalSuccAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + itemData.put("allAmount", totalSuccAmt); + // 实收金额转换 + BigDecimal totalFinalAmt = BigDecimal.valueOf(record.getTotalFinalAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + itemData.put("payAmount", totalFinalAmt); + // 退款金额转换 + BigDecimal refundAmount = BigDecimal.valueOf(record.getTotalRefundAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + itemData.put("refundAmount", refundAmount); + //手续费 + if (record.getTotalFeeAmt() != null){ + BigDecimal totalfeeamt = BigDecimal.valueOf(record.getTotalFeeAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + itemData.put("totalFeeAmt", totalfeeamt); + } + //手续费回退 + if (record.getTotalRefundFeeAmt() != null){ + BigDecimal totalReFeeAmt= BigDecimal.valueOf(record.getTotalRefundFeeAmt()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + itemData.put("totalRefundFeeAmt", totalReFeeAmt); + } + // 成功率 + itemData.put("round", record.getSuccRate() + "%"); + + if (StringUtils.isNotBlank(record.getDeviceType())) { + itemData.put("deviceType", PayOrder.DEVICE_TYPE_MAP.get(record.getDeviceType())); + } + + newList.add(itemData); + }); + + List linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), clazz); + // excel输出 + ExcelUtil.exportExcel(linkedList, title, title, clazz, title, response); + }catch (Exception e) { + logger.error("导出excel失败", e); + throw new BizException("导出订单失败!"); + } + + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/StatisticController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/StatisticController.java new file mode 100644 index 0000000..2fe1019 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/StatisticController.java @@ -0,0 +1,98 @@ +package com.jeequan.jeepay.agent.ctrl.statistics; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrderCount; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.PayOrder; +import com.jeequan.jeepay.service.impl.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 统计列表接口 + * + * @author xiaoyu + * + * @date 2022/5/23 16:52 + */ +@Slf4j +@RestController +@RequestMapping("/api/statistic") +public class StatisticController extends CommonCtrl { + + @Autowired private PayOrderService payOrderService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private StatsTradeService statsTradeService; + @Autowired private StatsChannelService statsChannelService; + @Autowired private StatsPayWayService statsPayWayService; + @Autowired private StatsDeviceService statsDeviceService; + + /** + * @author: xiaoyu + * @date: 2022/5/23 17:15 + * @describe: 统计列表 + */ + @PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + JSONObject paramJSON = getReqParamJSON(); + PayOrder payOrder = getObject(PayOrder.class); + List agentSubList = null; + // 交易报表 + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + // 查询服务商所有下级 + agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + } + String method = getValStringRequired("method"); + String mchNo = null; + Page mapPage = new Page<>(); + switch (method) { + case CS.STATISTIC_TYPE.MCH: + // 商户 + mapPage = statsTradeService.selectMchStatsList(paramJSON, agentSubList); + break; + case CS.STATISTIC_TYPE.AGENT: + // 服务商 + mapPage = statsTradeService.selectAgentStatsList(paramJSON, agentSubList); + break; + case CS.STATISTIC_TYPE.TRANSACTION: + mapPage = statsTradeService.selectTransactionStatsList(payOrder, paramJSON, agentSubList); + break; + case CS.STATISTIC_TYPE.STORE: + // 门店 + getValStringRequired("mchNo"); + mapPage = statsTradeService.selectStoreStatsList(paramJSON); + break; + case CS.STATISTIC_TYPE.WAY_CODE: + // 支付方式 + getValStringRequired("mchNo"); + mapPage = statsPayWayService.selectPayWayStatsList(paramJSON); + break; + case CS.STATISTIC_TYPE.WAY_CODE_TYPE: + // 支付类型 + getValStringRequired("mchNo"); + mapPage = statsPayWayService.selectWayCodeTypeStatsList(paramJSON); + break; + case CS.STATISTIC_TYPE.DEVICE: + // 设备 + mapPage = statsDeviceService.selectStatsList(paramJSON, agentSubList); + break; + default: + break; + } + // 解决hasnext不显示的问题 + mapPage.setCurrent(paramJSON.getIntValue("pageNumber")); + mapPage.setSize(paramJSON.getIntValue("pageSize")); + return ApiRes.page(mapPage); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/TotalStatisticController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/TotalStatisticController.java new file mode 100644 index 0000000..7caaed8 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/statistics/TotalStatisticController.java @@ -0,0 +1,109 @@ +package com.jeequan.jeepay.agent.ctrl.statistics; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrderCount; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.PayOrder; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.StatsDeviceService; +import com.jeequan.jeepay.service.impl.StatsPayWayService; +import com.jeequan.jeepay.service.impl.StatsTradeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 总计接口 + * + * @author xiaoyu + * + * @date 2022/5/23 16:52 + */ +@Slf4j +@RestController +@RequestMapping("/api/statistic/total") +public class TotalStatisticController extends CommonCtrl { + + @Autowired private AgentInfoService agentInfoService; + @Autowired private StatsTradeService statsTradeService; + @Autowired private StatsPayWayService statsPayWayService; + @Autowired private StatsDeviceService statsDeviceService; + + /** + * @author: xiaoyu + * @date: 2022/5/23 17:15 + * @describe: 总计 + */ + @PreAuthorize("hasAnyAuthority('ENT_STATISTIC_TRANSACTION', 'ENT_STATISTIC_MCH', 'ENT_STATISTIC_MCH_STORE', 'ENT_STATISTIC_MCH_WAY', 'ENT_STATISTIC_MCH_TYPE', 'ENT_STATISTIC_AGENT', 'ENT_STATISTIC_CHANNEL')") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes total() { + JSONObject paramJSON = getReqParamJSON(); + PayOrder payOrder = getObject(PayOrder.class); + + List agentSubList = null; + + if (StringUtils.isEmpty(payOrder.getAgentNo())) { + // 查询服务商所有下级 + agentSubList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + }else { + + } + String method = getValStringRequired("method"); + String mchNo = null; + PayOrderCount orderCount = new PayOrderCount(); + switch (method) { + case CS.STATISTIC_TYPE.MCH: + // 商户统计 + // resMap = payOrderService.totalByMch(payOrder, paramJSON, agentSubList); + orderCount = statsTradeService.selectTotalByTransaction(paramJSON, agentSubList); + break; + case CS.STATISTIC_TYPE.AGENT: + // 服务商统计 + // resMap = payOrderService.totalByAgent(payOrder, paramJSON, agentSubList); + orderCount = statsTradeService.selectTotalByAgent(paramJSON, agentSubList); + break; + case CS.STATISTIC_TYPE.TRANSACTION: + // 交易报表统计 + // resMap = payOrderService.totalByTransaction(payOrder, paramJSON, agentSubList); + orderCount = statsTradeService.selectTotalByTransaction(paramJSON, agentSubList, false); + break; + case CS.STATISTIC_TYPE.STORE: + // 门店统计 + getValStringRequired("mchNo"); + // payOrder.setMchNo(mchNo); + // resMap = payOrderService.totalByStore(payOrder, paramJSON); + orderCount = statsTradeService.selectTotalByStore(paramJSON, null); + break; + case CS.STATISTIC_TYPE.WAY_CODE: + // 支付方式统计 + getValStringRequired("mchNo"); + // payOrder.setMchNo(mchNo); + // resMap = payOrderService.totalByWayCode(payOrder, paramJSON); + orderCount = statsPayWayService.selectTotalByPayWay(paramJSON); + break; + case CS.STATISTIC_TYPE.WAY_CODE_TYPE: + // 支付类型统计 + getValStringRequired("mchNo"); + // payOrder.setMchNo(mchNo); + // resMap = payOrderService.totalByWayCodeType(payOrder, paramJSON); + orderCount = statsPayWayService.selectTotalByWayCodeType(paramJSON); + break; + case CS.STATISTIC_TYPE.DEVICE: + // 设备统计 + // resMap = payOrderService.totalByDevice(payOrder, paramJSON, agentSubList); + orderCount = statsDeviceService.selectTotalByDeviceNo(paramJSON, agentSubList); + break; + default: + break; + } + return ApiRes.ok(orderCount); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/DeviceProvideConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/DeviceProvideConfigController.java new file mode 100644 index 0000000..e17e436 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/DeviceProvideConfigController.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.agent.ctrl.store; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.DeviceProvideConfig; +import com.jeequan.jeepay.service.impl.DeviceProvideConfigService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 设备厂商配置管理类 + * + * @author zx + * @date 2021-12-28 09:15 + */ +@Slf4j +@RestController +@RequestMapping("api/device/provider") +public class DeviceProvideConfigController extends CommonCtrl { + + @Autowired private DeviceProvideConfigService deviceProvideConfigService; + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 厂商配置列表 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_LIST', 'ENT_DEVICE_PRINTER_LIST', 'ENT_DEVICE_SPEAKER_ADD'," + + "'ENT_DEVICE_PRINTER_ADD', 'ENT_DEVICE_SPEAKER_EDIT', 'ENT_DEVICE_PRINTER_EDIT')") + @GetMapping + public ApiRes pages() { + LambdaQueryWrapper gw = DeviceProvideConfig.gw(); + gw.select(DeviceProvideConfig::getConfigId, DeviceProvideConfig::getConfigDesc, DeviceProvideConfig::getProvider); + + gw.orderByDesc(DeviceProvideConfig::getCreatedAt); + gw.eq(DeviceProvideConfig::getDeviceType, getValByteRequired("deviceType")); + + if (null != getValByte("state")) { + gw.eq(DeviceProvideConfig::getState, getValByte("state")); + } + + gw.select(DeviceProvideConfig::getConfigId, DeviceProvideConfig::getConfigDesc, DeviceProvideConfig::getDeviceType, DeviceProvideConfig::getProvider, + DeviceProvideConfig::getCreatedAt, DeviceProvideConfig::getAppId, DeviceProvideConfig::getState); + + IPage page = deviceProvideConfigService.page(getIPage(true), gw); + //返回数据 + return ApiRes.page(page); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreController.java new file mode 100644 index 0000000..93ec4b9 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreController.java @@ -0,0 +1,201 @@ +package com.jeequan.jeepay.agent.ctrl.store; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBApiMapConfig; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchStore; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.MchStoreService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +/** + * 商户门店管理 + * + * @date 2021/12/29 9:52 + */ +@RestController +@RequestMapping("/api/mchStore") +public class MchStoreController extends CommonCtrl { + + @Autowired private MchStoreService mchStoreService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private MchInfoService mchInfoService; + @Autowired + private MchApplymentService mchApplymentService; + + + /** + * @date: 2021/12/29 9:53 + * @describe: 门店列表查询 + */ + @GetMapping + @PreAuthorize("hasAuthority('ENT_MCH_STORE_LIST')") + public ApiRes list() { + MchStore mchStore = getObject(MchStore.class); + //mchStore.setAgentNo(getCurrentAgentNo()); + JSONObject paramJSON = getReqParamJSON(); + // 可查看自己和全部下级服务商 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + if (CollectionUtil.isNotEmpty(subAgentNoList)) { + mchStore.setSubAgentNoList(subAgentNoList); + } + IPage mchStoreList = mchStoreService.listByPage(getIPage(true), mchStore, paramJSON); + return ApiRes.page(mchStoreList); + } + + /** + * @date: 2021/12/29 9:59 + * @describe: 新建门店 + */ + @MethodLog(remark = "新建门店") + @PostMapping + @PreAuthorize("hasAuthority('ENT_MCH_STORE_ADD')") + public ApiRes add() { + MchStore mchStore = getObject(MchStore.class); + + Assert.hasLength(mchStore.getMchNo(), "用户号[mchNo]不能为空"); + + Assert.notNull(mchStore.getAreaCode(), "请选择省市区"); + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + Assert.hasLength(mchStore.getMchApplyId(), "商户号[mchApplyId]不能为空"); + + MchApplyment tbMchApplyment = mchApplymentService.getById(mchStore.getMchApplyId()); + Assert.notNull(tbMchApplyment, "商户不存在"); + + //关联商户信息(原进件信息)t_mch_applyment,需要校验商户状态,必须是进件成功的 + if (MchApplyment.STATE_SUCCESS != tbMchApplyment.getState()) { + return ApiRes.customFail("该商户状态未进件成功!"); + } + + //校验指定商户号下的进件信息 + String applyMchNo = tbMchApplyment.getMchNo(); + String storeMchNo = mchStore.getMchNo(); + + if (!applyMchNo.equals(storeMchNo)) { + return ApiRes.customFail("用户信息与商户信息不匹配!"); + } + + mchStore.setStoreId(SeqKit.genStoreNo()); + mchStore.setAgentNo(agentInfo.getAgentNo()); + mchStore.setTopAgentNo(agentInfoService.queryTopAgentNo(getCurrentAgentNo())); + + mchStore.setIsvNo(agentInfo.getIsvNo()); + // 初始为非默认门店 + mchStore.setDefaultFlag(CS.NO); + boolean result = mchStoreService.save(mchStore); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE); + } + return ApiRes.ok(); + } + + /** + * @date: 2021/12/29 9:59 + * @describe: 门店详情 + */ + @GetMapping("/{recordId}") + @PreAuthorize("hasAuthority('ENT_MCH_STORE_VIEW')") + public ApiRes detail(@PathVariable("recordId") String recordId) { + + MchStore mchStore = mchStoreService.getById(recordId); + if (mchStore == null || !mchStore.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + MchInfo mchInfo = mchInfoService.getById(mchStore.getMchNo()); + mchStore.addExt("mchName", mchInfo.getMchName()); + + return ApiRes.ok(mchStore); + } + + /** + * @date: 2021/12/29 10:00 + * @describe: 更新门店 + */ + @MethodLog(remark = "更新门店") + @PutMapping("/{recordId}") + @PreAuthorize("hasAuthority('ENT_MCH_STORE_EDIT')") + public ApiRes update(@PathVariable("recordId") String recordId) { + + MchStore mchStore = getObject(MchStore.class); + mchStore.setStoreId(recordId); + mchStore.setMchNo(null); + mchStore.setAgentNo(null); + mchStore.setTopAgentNo(null); + mchStore.setCreatedAt(null); + mchStore.setUpdatedAt(null); + MchStore dbRecord = mchStoreService.getById(recordId); + if (!dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("无权操作!"); + } + + // 如果修改当前为默认 + if (mchStore.getDefaultFlag() == CS.YES) { + mchStoreService.updateAllDefaultFlag(dbRecord.getMchNo()); + }else { + mchStore.setDefaultFlag(null); + } + + boolean result = mchStoreService.updateById(mchStore); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + return ApiRes.ok(); + } + + /** + * @date: 2021/12/29 10:05 + * @describe: 删除门店 + */ + @MethodLog(remark = "删除门店") + @DeleteMapping("/{recordId}") + @PreAuthorize("hasAuthority('ENT_MCH_STORE_DELETE')") + public ApiRes delete(@PathVariable("recordId") String recordId) { + MchStore mchStore = mchStoreService.getById(recordId); + + if (!mchStore.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("无权操作!"); + } + if (mchStore.getDefaultFlag() == CS.YES) { + throw new BizException("默认门店无法删除!"); + } + + mchStoreService.deleteStore(recordId, false); + return ApiRes.ok(); + } + + + /** + * @date: 2022/2/19 10:41 + * @describe: 获取地图配置参数 + */ + @GetMapping("/mapConfig") + @PreAuthorize("hasAuthority('ENT_MCH_STORE_MAP')") + public ApiRes getMapConfig() { + DBApiMapConfig apiMapConfig = sysConfigService.getDBApiMapConfig(); + return ApiRes.ok(apiMapConfig); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreDeviceController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreDeviceController.java new file mode 100644 index 0000000..24e5c9b --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/store/MchStoreDeviceController.java @@ -0,0 +1,466 @@ +package com.jeequan.jeepay.agent.ctrl.store; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 设备厂商配置管理类 + * + * @author zx + * + * @date 2021-12-28 09:15 + */ +@Slf4j +@RestController +@RequestMapping("api/store/device") +public class MchStoreDeviceController extends CommonCtrl { + + @Autowired private DeviceProvideConfigService deviceProvideConfigService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private MchStoreService mchStoreService; + @Autowired private MchAppService mchAppService; + @Autowired private MchQrcDeviceRelaService mchQrcDeviceRelaService; + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 门店设备列表 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_LIST', 'ENT_DEVICE_PRINTER_DEVICE_LIST', 'ENT_DEVICE_POS_DEVICE_LIST', " + + "'ENT_DEVICE_PLUGIN_CDKEY_LIST', 'ENT_DEVICE_FACE_APP_LIST')") + @GetMapping + public ApiRes pages() { + + MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class); + + // 可查看自己和全部下级代理的设备 + String currentAgentNo = getCurrentAgentNo(); + List subAgentNoList = agentInfoService.queryAllSubAgentNo(currentAgentNo); + if (CollectionUtil.isNotEmpty(subAgentNoList)) { + mchStoreDevice.setSubAgentNoList(subAgentNoList); + } + + IPage page = mchStoreDeviceService.selectPage(getIPage(), mchStoreDevice); + if (page.getTotal() == 0) { + return ApiRes.page(page); + } + // 列表添加是否属于自身,设备只能绑定直属商户,app端展示隐藏也使用此字段 + for (MchStoreDevice device: page.getRecords()) { + if (currentAgentNo.equals(device.getAgentNo())) { + device.addExt("isSelf", true); + } + } + + //返回数据 + return ApiRes.page(page); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 门店设备修改 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT', " + + "'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')") + @MethodLog(remark = "设备厂商配置修改") + @PutMapping("/{deviceId}") + public ApiRes update(@PathVariable("deviceId") Long deviceId) { + MchStoreDevice mchStoreDevice = getObject(MchStoreDevice.class); + mchStoreDevice.setDeviceId(deviceId); + mchStoreDevice.setBatchId(null); + mchStoreDevice.setDeviceNo(null); + mchStoreDevice.setDeviceParams(null); + mchStoreDevice.setCreatedAt(null); + mchStoreDevice.setUpdatedAt(null); + + // 可查看自己和全部下级代理的设备 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId); + if (!subAgentNoList.contains(dbRecord.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + boolean result = mchStoreDeviceService.updateById(mchStoreDevice); + if(!result) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + + return ApiRes.ok(); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 根据ID获取门店设备 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_VIEW', 'ENT_DEVICE_PRINTER_DEVICE_VIEW', 'ENT_DEVICE_POS_DEVICE_VIEW', " + + "'ENT_DEVICE_PLUGIN_CDKEY_VIEW', 'ENT_DEVICE_FACE_APP_VIEW')") + @GetMapping("/{deviceId}") + public ApiRes get(@PathVariable("deviceId") Long deviceId) { + // 可查看自己和全部下级代理的设备 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId); + if (!subAgentNoList.contains(dbRecord.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + // 设备是否属于自身 + if (getCurrentAgentNo().equals(dbRecord.getAgentNo())) { + dbRecord.addExt("isSelf", true); + } + + // 添加服务商、商户、门店名称 + AgentInfo allotAgent = agentInfoService.getById(dbRecord.getAgentNo()); + if (allotAgent != null) { + dbRecord.addExt("agentName", allotAgent.getAgentName()); + } + if (dbRecord.getBindState() == CS.YES) { + if (StringUtils.isNotBlank(dbRecord.getMchNo())) { + MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo()); + if (mchInfo != null) { + dbRecord.addExt("mchName", mchInfo.getMchName()); + } + } + + if (StringUtils.isNotBlank(dbRecord.getAppId())) { + MchAppEntity mchAppEntity = mchAppService.getById(dbRecord.getAppId()); + if (mchAppEntity != null) { + dbRecord.addExt("appName", mchAppEntity.getAppName()); + } + } + + if (dbRecord.getStoreId() != null) { + MchStore mchStore = mchStoreService.getById(dbRecord.getStoreId()); + if (mchStore != null) { + dbRecord.addExt("storeName", mchStore.getStoreName()); + } + } + } + + List relaList = mchQrcDeviceRelaService.list(MchQrcDeviceRela.gw().eq(MchQrcDeviceRela::getDeviceId, deviceId)); + if (!CollectionUtils.isEmpty(relaList)) { + dbRecord.addExt("qrcIdList", relaList.stream().map(MchQrcDeviceRela::getQrcId).collect(Collectors.toList())); + } + + return ApiRes.ok(dbRecord); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 播报测试 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_TEST')") + @PostMapping("/speak/{deviceId}") + public ApiRes speak(@PathVariable("deviceId") Long deviceId) { + + Long amountL = getRequiredAmountL("amount"); + + // 可查看自己和全部下级代理的设备 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + + MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId); + if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) { + return ApiRes.customFail("设备不存在或已禁用"); + } + + DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId()); + if (provideConfig == null || provideConfig.getState() != CS.YES) { + return ApiRes.customFail("设备厂商未配置或已禁用"); + } + + // 设备类型 + String provider = mchStoreDevice.getProvider(); + ISpeakerService speakerService = SpringBeansUtil.getBean(provider + "SpeakerService", ISpeakerService.class); + + // 设备参数 + JSONObject deviceParams = new JSONObject(); + deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams()); + deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams()); + deviceParams.put("providerParams", provideConfig.getProviderParams()); + + // 消息内容 + PayOrderInfo4Device speakPayOrderInfo = new PayOrderInfo4Device(); + speakPayOrderInfo.setAmount(amountL); + speakPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT); + speakPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis())); + + try { + speakerService.send(deviceParams, speakPayOrderInfo); + return ApiRes.ok(); + }catch (BizException e) { + throw e; + } + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 打印测试 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_TEST')") + @PostMapping("/print/{deviceId}") + public ApiRes print(@PathVariable("deviceId") Long deviceId) { + + Long amountL = getRequiredAmountL("amount"); + + // 可查看自己和全部下级代理的设备 + List subAgentNoList = agentInfoService.queryAllSubAgentNo(getCurrentAgentNo()); + + MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId); + if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES || !subAgentNoList.contains(mchStoreDevice.getAgentNo())) { + return ApiRes.customFail("设备不存在或已禁用"); + } + + DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId()); + if (provideConfig == null || provideConfig.getState() != CS.YES) { + return ApiRes.customFail("设备厂商未配置或已禁用"); + } + + // 设备类型 + String provider = mchStoreDevice.getProvider(); + IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class); + + // 设备参数 + JSONObject deviceParams = new JSONObject(); + deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams()); + deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams()); + deviceParams.put("providerParams", provideConfig.getProviderParams()); + + // 消息内容 + PayOrderInfo4Device printPayOrderInfo = new PayOrderInfo4Device(); + printPayOrderInfo.setAmount(amountL); + printPayOrderInfo.setWayCodeType(CS.PAY_WAY_CODE_TYPE.WECHAT); + printPayOrderInfo.setPayOrderId(String.valueOf(DateKit.currentTimeMillis())); + printPayOrderInfo.setCreatedAt(DateUtil.date()); + + try { + printerService.send(deviceParams, printPayOrderInfo); + return ApiRes.ok(); + }catch (BizException e) { + throw e; + } + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 清空打印队列 + */ + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_PRINTER_DEVICE_CLEAR')") + @PostMapping("/clear/{deviceId}") + public ApiRes clear(@PathVariable("deviceId") Long deviceId) { + + MchStoreDevice mchStoreDevice = mchStoreDeviceService.getById(deviceId); + if (mchStoreDevice == null || mchStoreDevice.getState() != CS.YES) { + return ApiRes.customFail("设备不存在"); + } + + DeviceProvideConfig provideConfig = deviceProvideConfigService.getById(mchStoreDevice.getConfigId()); + if (provideConfig == null || provideConfig.getState() != CS.YES) { + return ApiRes.customFail("设备厂商未配置"); + } + + // 设备类型 + String provider = mchStoreDevice.getProvider(); + IPrinterService printerService = SpringBeansUtil.getBean(provider + "PrinterService", IPrinterService.class); + + // 设备参数 + JSONObject deviceParams = new JSONObject(); + deviceParams.put("deviceParams", mchStoreDevice.getDeviceParams()); + deviceParams.put("bizConfigParams", mchStoreDevice.getBizConfigParams()); + deviceParams.put("providerParams", provideConfig.getProviderParams()); + + try { + printerService.clearPrinter(deviceParams); + return ApiRes.ok(); + }catch (Exception e) { + return ApiRes.customFail(e.getMessage()); + } + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 绑定设备 + */ + @MethodLog(remark = "绑定设备") + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," + + "'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')") + @PutMapping("/bind/{deviceId}") + public ApiRes bind(@PathVariable("deviceId") Long deviceId) { + + String mchNo = getValStringRequired("mchNo"); + String storeId = getValStringRequired("storeId"); + Byte bindType = getValByte("bindType"); + + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("商户不存在"); + } + + MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId); + if (dbRecord == null || StringUtils.isBlank(dbRecord.getAgentNo()) || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + // 除云喇叭和云打印外的设备 需绑定商户应用 + String appId = ""; + if (dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_SPEAKER && dbRecord.getDeviceType() != MchStoreDevice.DEVICE_TYPE_PRINTER) { + appId = getValStringRequired("appId"); + } + + MchStoreDevice updateRecord = new MchStoreDevice(); + updateRecord.setDeviceId(deviceId).setMchNo(mchNo).setAppId(appId).setStoreId(storeId).setBindState(CS.YES); + if (null != bindType) { + updateRecord.setBindType(bindType); + } + + // 云喇叭 同步绑定码牌 + if (dbRecord.getDeviceType() == MchStoreDevice.DEVICE_TYPE_SPEAKER) { + + String qrcIdListStr = getValString("qrcIdList"); + + // 云喇叭绑定类型 为码牌时,需传入绑定的码牌id + List qrcList = new LinkedList<>(); + if (null != bindType && bindType == MchStoreDevice.DEVICE_BIND_TYPE_QRC && StringUtils.isNotBlank(qrcIdListStr)) { + qrcList = JSONArray.parseArray(qrcIdListStr, Long.class); + } + + boolean result = mchStoreDeviceService.bindSpeakerDevice(updateRecord, dbRecord.getBindQrcId(), qrcList); + if (!result) { + return ApiRes.customFail("绑定失败"); + } + return ApiRes.ok(); + } + + // 云打印、扫码pos执行更新 + if (mchStoreDeviceService.updateById(updateRecord)) { + return ApiRes.ok(); + } + + return ApiRes.customFail("绑定失败"); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 解绑设备 + */ + @MethodLog(remark = "解绑设备") + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_EDIT', 'ENT_DEVICE_PRINTER_DEVICE_EDIT', 'ENT_DEVICE_POS_DEVICE_EDIT'," + + " 'ENT_DEVICE_PLUGIN_CDKEY_EDIT', 'ENT_DEVICE_FACE_APP_EDIT')") + @PostMapping("/unbind/{deviceId}") + public ApiRes unbind(@PathVariable("deviceId") Long deviceId) { + + MchStoreDevice dbRecord = mchStoreDeviceService.getById(deviceId); + if (dbRecord == null || dbRecord.getBindState() == CS.NO || !dbRecord.getAgentNo().equals(getCurrentAgentNo())) { + return ApiRes.customFail("解绑失败"); + } + + MchInfo mchInfo = mchInfoService.getById(dbRecord.getMchNo()); + if (mchInfo == null || StringUtils.isBlank(mchInfo.getAgentNo()) || !mchInfo.getAgentNo().equals(getCurrentAgentNo())) { + throw new BizException("当前解绑设备不属于您的直属商户,无法解绑!"); + } + + mchStoreDeviceService.unbind(dbRecord); + + return ApiRes.ok(); + } + + /** + * @author: zx + * @date: 2021-12-28 09:15 + * @describe: 划拨/收回设备 + */ + @MethodLog(remark = "划拨/收回设备") + @PreAuthorize("hasAnyAuthority('ENT_DEVICE_SPEAKER_DEVICE_ALLOT', 'ENT_DEVICE_PRINTER_DEVICE_ALLOT', " + + "'ENT_DEVICE_POS_DEVICE_ALLOT', 'ENT_DEVICE_PLUGIN_CDKEY_ALLOT', 'ENT_DEVICE_FACE_APP_ALLOT')") + @PostMapping("/allotDevice") + public ApiRes allotDevice() { + + // 服务商是否支持划拨码牌、设备 + SysConfig isSupportAgentAllot = sysConfigService.getById("isSupportAgentAllot"); + if(isSupportAgentAllot == null || String.valueOf(CS.NO).equals(isSupportAgentAllot.getConfigVal())){ + throw new BizException("不支持服务商划拨码牌、设备"); + } + + String allotType = getValStringRequired("allotType"); // 划拨类型:select-勾选划拨 batch-批次划拨 + String allotOrRecover = getValStringRequired("allotOrRecover"); // 分配类型:allot-划拨 recover-收回 + + // 构建批量更新设备ID集合 + List list; + if (allotType.equals("select")) { + + String allotDeviceIds = getValStringRequired("allotDeviceIds"); + list = mchStoreDeviceService.list(MchStoreDevice.gw().in(MchStoreDevice::getDeviceId, Arrays.asList(allotDeviceIds.split(",")))); + + }else if (allotType.equals("batch")) { + + String batchId = getValStringRequired("batchId"); + list = mchStoreDeviceService.list(MchStoreDevice.gw().eq(MchStoreDevice::getBatchId, batchId)); + + }else { + throw new BizException("划拨类型错误"); + } + if (CollUtil.isEmpty(list)) { + throw new BizException("请选择设备"); + } + + + // 当前代理只可划拨自己和直接下级代理的设备 + List subAgentNoList = agentInfoService.querySubAgentNo(getCurrentAgentNo()); + for (MchStoreDevice mchStoreDevice: list) { + if (!subAgentNoList.contains(mchStoreDevice.getAgentNo())) { + throw new BizException("存在不可划拨设备【设备号:" + mchStoreDevice.getDeviceNo() + "】"); + } + } + + List deviceIdList = list.stream().map(MchStoreDevice::getDeviceId).collect(Collectors.toList()); + + // 1、收回设备 + if (allotOrRecover.equals("recover")) { + mchStoreDeviceService.recoverDevice(true, deviceIdList, subAgentNoList, getCurrentAgentNo()); + return ApiRes.ok(); + } + + // 2、划拨设备 + String agentNo = getValStringRequired("agentNo"); + List mchNoList = getMchNoListByAgentNo(agentNo); + + mchStoreDeviceService.allotDevice(true, agentNo, deviceIdList, mchNoList, subAgentNoList); + + return ApiRes.ok(); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/AdvertController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/AdvertController.java new file mode 100644 index 0000000..b6b4f59 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/AdvertController.java @@ -0,0 +1,159 @@ +package com.jeequan.jeepay.agent.ctrl.subagent; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.SysAdvertConfig; +import com.jeequan.jeepay.service.impl.SysAdvertConfigService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 广告 + * + * @author xiaoyu + * + * @date 2023/2/21 16:13 + */ +@RestController +@RequestMapping("/api/advert") +public class AdvertController extends CommonCtrl { + + @Autowired SysAdvertConfigService advertConfigService; + + /** APP 展业宝广告 **/ + @GetMapping("/appAdvert") + public ApiRes appAdvert() { + + // 广告位置 1-启动页 2-首页 3-我的页 + Byte appPlace = getValByteRequired("appPlace"); + // 查询平台全局广告 + LambdaQueryWrapper wrapper = SysAdvertConfig.gw(); + wrapper.eq(SysAdvertConfig::getAdvertType, SysAdvertConfig.ADVERT_TYPE_APP_AGENT); + wrapper.eq(SysAdvertConfig::getAppPlace, appPlace); + wrapper.eq(SysAdvertConfig::getReleaseState, CS.YES); + wrapper.orderByAsc(SysAdvertConfig::getAdvertSort); + wrapper.orderByDesc(SysAdvertConfig::getCreatedAt); + List list = advertConfigService.list(wrapper); + return ApiRes.ok(list); + } + + /** + * @author: xiaoyu + * @date: 2023/2/20 11:06 + * @describe: 广告配置列表 + */ + @PreAuthorize("hasAnyAuthority('ENT_ADVERT_LIST', 'ENT_ADVERT_VIEW')") + @GetMapping + public ApiRes pages() { + + SysAdvertConfig record = getObject(SysAdvertConfig.class); + + LambdaQueryWrapper condition = SysAdvertConfig.gw(); + condition.eq(record.getAdvertId() != null, SysAdvertConfig::getAdvertId, record.getAdvertId()); + condition.eq(record.getAppPlaceType() != null, SysAdvertConfig::getAppPlaceType, record.getAppPlaceType()); + condition.eq(record.getReleaseState() != null, SysAdvertConfig::getReleaseState, record.getReleaseState()); + condition.eq(record.getAdvertType() != null, SysAdvertConfig::getAdvertType, record.getAdvertType()); + condition.eq(record.getAppPlace() != null, SysAdvertConfig::getAppPlace, record.getAppPlace()); + condition.like(StringUtils.isNotEmpty(record.getTitle()), SysAdvertConfig::getTitle, record.getTitle()); + condition.eq(StringUtils.isNotEmpty(record.getMchNo()), SysAdvertConfig::getMchNo, record.getMchNo()); + condition.eq(SysAdvertConfig::getAgentNo, getCurrentAgentNo()); + condition.orderByDesc(SysAdvertConfig::getCreatedAt); + IPage pages = advertConfigService.page(getIPage(), condition); + + for (SysAdvertConfig config: pages.getRecords()) { + if (StringUtils.isNotEmpty(config.getMchNo())) { + MchInfo mchInfo = mchInfoService.getById(config.getMchNo()); + if (mchInfo != null) { + config.addExt("infoName", mchInfo.getMchName()); + }else { + config.addExt("infoName", ""); + } + } + } + + //返回数据 + return ApiRes.ok(pages); + } + + /** detail */ + @PreAuthorize("hasAuthority( 'ENT_ADVERT_VIEW' )") + @RequestMapping(value="/{advertId}", method = RequestMethod.GET) + public ApiRes getConfigs(@PathVariable("advertId") Long advertId) { + SysAdvertConfig config = advertConfigService.getOne( + SysAdvertConfig.gw() + .eq(SysAdvertConfig::getAdvertId, advertId) + .eq(SysAdvertConfig::getAgentNo, getCurrentAgentNo()) + ); + return ApiRes.ok(config); + } + + /** + * @author: xiaoyu + * @date: 2023/2/20 11:06 + * @describe: 广告配置修改 + */ + @PreAuthorize("hasAnyAuthority('ENT_ADVERT_EDIT')") + @MethodLog(remark = "广告配置修改") + @RequestMapping(value="/{advertId}", method = RequestMethod.PUT) + public ApiRes update(@PathVariable("advertId") Long advertId) { + // 校验权限 + SysAdvertConfig config = advertConfigService.getById(advertId); + if (config != null && !getCurrentAgentNo().equals(config.getAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + SysAdvertConfig record = getObject(SysAdvertConfig.class); + record.setAdvertId(advertId); + if (getReqParamJSON().getByte("state") != null) { + record.setReleaseState(getReqParamJSON().getByte("state")); + } + + advertConfigService.updateAdvert(record); + return ApiRes.ok(); + } + + /** + * @author: xiaoyu + * @date: 2023/2/20 11:10 + * @describe: 广告配置新增 + */ + @PreAuthorize("hasAuthority( 'ENT_ADVERT_ADD' )") + @MethodLog(remark = "广告配置新增") + @RequestMapping(value="", method = RequestMethod.POST) + public ApiRes add() { + JSONObject paramJSON = getReqParamJSON(); + SysAdvertConfig record = getObject(SysAdvertConfig.class); + String infoIds = paramJSON.getString("infoIds"); + record.setAgentNo(getCurrentAgentNo()); + record.setCreatedUid(getCurrentUser().getSysUserId()); + record.setCreatedBy(getCurrentUser().getSysUser().getRealname()); + advertConfigService.addConfig(infoIds, record); + return ApiRes.ok(); + } + + /** delete */ + @PreAuthorize("hasAuthority('ENT_ADVERT_DEL')") + @MethodLog(remark = "广告配置删除") + @DeleteMapping + public ApiRes del() { + String delAdvertIds = getValStringRequired("delAdvertIds"); + List advertIdList = Arrays.stream(delAdvertIds.split(",")).collect(Collectors.toList()); + advertConfigService.removeConfig(advertIdList, getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT); + return ApiRes.ok(); + + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/SubAgentInfoController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/SubAgentInfoController.java new file mode 100644 index 0000000..e34364a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/subagent/SubAgentInfoController.java @@ -0,0 +1,183 @@ +package com.jeequan.jeepay.agent.ctrl.subagent; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.components.mq.model.CleanAgentLoginAuthCacheMQ; +import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ; +import com.jeequan.jeepay.components.mq.vender.IMQSender; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.MchInfo; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +/*** +* 服务商管理 +* +* @author terrfly +* +* @date 2022/3/15 15:25 +*/ +@RestController +@RequestMapping("/api/subAgents") +public class SubAgentInfoController extends CommonCtrl { + + @Autowired private IMQSender mqSender; + @Autowired private SmsManager smsManager; + + @PreAuthorize("hasAuthority('ENT_AGENT_LIST')") + @GetMapping + public ApiRes list() { + AgentInfo agentInfo = getObject(AgentInfo.class); + + LambdaQueryWrapper wrapper = AgentInfo.gw(); + wrapper.eq(AgentInfo::getPid, getCurrentAgentNo()); + wrapper.eq(StringUtils.isNotEmpty(agentInfo.getAgentNo()), AgentInfo::getAgentNo, agentInfo.getAgentNo()); + wrapper.eq(StringUtils.isNotEmpty(agentInfo.getIsvNo()), AgentInfo::getIsvNo, agentInfo.getIsvNo()); + wrapper.like(StringUtils.isNotEmpty(agentInfo.getAgentName()), AgentInfo::getAgentName, agentInfo.getAgentName()); + wrapper.eq(agentInfo.getState() != null, AgentInfo::getState, agentInfo.getState()); + wrapper.like(StringUtils.isNotEmpty(agentInfo.getContactTel()), AgentInfo::getContactTel, agentInfo.getContactTel()); + wrapper.like(StringUtils.isNotEmpty(agentInfo.getLoginUsername()), AgentInfo::getLoginUsername, agentInfo.getLoginUsername()); + wrapper.orderByDesc(AgentInfo::getCreatedAt); + + // app端 联合模糊查询字段 + String unionAgentInfo = getValString("unionAgentInfo"); + if (StringUtils.isNotBlank(unionAgentInfo)) { + wrapper.and(i -> i.like(AgentInfo::getAgentNo, unionAgentInfo) + .or().like(AgentInfo::getAgentName, unionAgentInfo) + .or().like(AgentInfo::getContactTel, unionAgentInfo)); + } + + IPage pages = agentInfoService.page(getIPage(), wrapper); + for (AgentInfo info:pages.getRecords()) { + info.setContactTel(DesensitizedUtil.mobilePhone(info.getContactTel())); + long count = mchInfoService.count(MchInfo.gw().eq(MchInfo::getAgentNo, info.getAgentNo())); + info.addExt("mchCount", count); + } + return ApiRes.page(pages); + } + + @PreAuthorize("hasAuthority('ENT_AGENT_INFO_ADD')") + @MethodLog(remark = "新增服务商") + @PostMapping + public ApiRes add() { + // 当前服务商是否允许发展下级代理 + AgentInfo pAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + if (pAgentInfo.getAddAgentFlag() != CS.YES) { + throw new BizException("当前服务商不可发展下级服务商"); + } + + AgentInfo agentInfo = getObject(AgentInfo.class); + agentInfo.setPid(getCurrentAgentNo()); + + AgentInfo thisAgent = agentInfoService.getById(getCurrentAgentNo()); + agentInfo.setIsvNo(thisAgent.getIsvNo()); + + // 获取传入的服务商登录名、登录密码 + String loginPassword = getValString("loginPassword"); + Byte isNotify = getValByteRequired("isNotify"); + + if (StringUtils.isBlank(loginPassword)) { + loginPassword = null; + } + agentInfo.setAgentNo("P" + DateUtil.format(new Date(), "yyMMdd")+ RandomUtil.randomNumbers(6)); + // 当前登录用户信息 + SysUser sysUser = getCurrentUser().getSysUser(); + agentInfo.setCreatedUid(sysUser.getSysUserId()); + agentInfo.setCreatedBy(sysUser.getRealname()); + + agentInfoService.addAgentV2(agentInfo, loginPassword, true); + + // 发送短信通知 + if (isNotify == CS.YES) { + smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(agentInfo.getContactTel(), agentInfo.getLoginUsername(), loginPassword)); + } + return ApiRes.ok(); + } + + @PreAuthorize("hasAuthority('ENT_AGENT_INFO_DEL')") + @MethodLog(remark = "删除服务商") + @DeleteMapping(value="/{agentNo}") + public ApiRes delete(@PathVariable("agentNo") String agentNo) { + + List userIdList = agentInfoService.removeByAgentNo(agentNo); + // 推送mq删除redis用户缓存 + mqSender.send(CleanAgentLoginAuthCacheMQ.build(userIdList)); + + return ApiRes.ok(); + } + + @PreAuthorize("hasAuthority('ENT_AGENT_INFO_EDIT')") + @MethodLog(remark = "更新服务商信息") + @PutMapping(value="/{agentNo}") + public ApiRes update(@PathVariable("agentNo") String agentNo) { + + AgentInfo dbAgentInfo = agentInfoService.getById(agentNo); + if (dbAgentInfo == null) { + throw new BizException("服务商信息不存在"); + } + + //获取查询条件 + AgentInfo agentInfo = getObject(AgentInfo.class); + agentInfo.setAgentNo(agentNo); //设置服务商号主键 + + agentInfo.setIsvNo(null); // 不允许更改 + agentInfo.setPid(null); + agentInfo.setLoginUsername(null); // 防止修改用户登录名 + + + boolean resetPass = getReqParamJSON().getBooleanValue("resetPass"); + String confirmPwd = null; + if(resetPass){ + confirmPwd = Boolean.TRUE.equals(getReqParamJSON().getBoolean("defaultPass")) ? null : Base64.decodeStr(getValStringRequired("confirmPwd")); + } + + // 判断要修改的服务商信息是否需要审核 如果为审核失败/待认证->待审核 + if (dbAgentInfo.getState() == AgentInfo.AUDIT_STATE_FALSE || dbAgentInfo.getState() == AgentInfo.AUDIT_STATE_UN_AUTH) { + agentInfo.setState(AgentInfo.AUDIT_STATE_ING); + } + + // 更新 & 得到需要删除的用户ID的记录 + Set removeCacheUserIdList = agentInfoService.updateAgent(agentInfo, getReqParamJSON(), resetPass, confirmPwd); + + // 推送mq删除redis用户认证信息 + if (!removeCacheUserIdList.isEmpty()) { + mqSender.send(CleanAgentLoginAuthCacheMQ.build(new ArrayList<>(removeCacheUserIdList))); + } + + // 推送mq到目前节点进行更新数据 + mqSender.send(ResetIsvMchAppInfoConfigMQ.build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, agentNo, null)); + + return ApiRes.ok(); + } + + @PreAuthorize("hasAnyAuthority('ENT_AGENT_INFO_EDIT', 'ENT_AGENT_INFO_VIEW')") + @GetMapping(value="/{agentNo}") + public ApiRes detail(@PathVariable("agentNo") String agentNo) { + AgentInfo agentInfo = agentInfoService.getById(agentNo); + if (agentInfo == null || !agentInfo.getPid().equals(getCurrentAgentNo())) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + return ApiRes.ok(agentInfo); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysEntController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysEntController.java new file mode 100644 index 0000000..e5c7411 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysEntController.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.TreeDataBuilder; +import com.jeequan.jeepay.db.entity.SysEntitlement; +import com.jeequan.jeepay.service.impl.SysEntitlementService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 权限菜单管理类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/sysEnts") +public class SysEntController extends CommonCtrl { + + @Autowired SysEntitlementService sysEntitlementService; + + /** 查询权限集合 */ + @PreAuthorize("hasAnyAuthority( 'ENT_UR_ROLE_ENT_LIST', 'ENT_UR_ROLE_DIST' )") + @RequestMapping(value="/showTree", method = RequestMethod.GET) + public ApiRes showTree() { + + //查询全部数据 + List list = sysEntitlementService.list(SysEntitlement.gw().eq(SysEntitlement::getSysType, CS.SYS_ROLE_TYPE.AGENT)); + + //4. 转换为json树状结构 + JSONArray jsonArray = (JSONArray) JSONArray.toJSON(list); + List leftMenuTree = new TreeDataBuilder(jsonArray, + "entId", "pid", "children", "entSort", true) + .buildTreeObject(); + + return ApiRes.ok(leftMenuTree); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleController.java new file mode 100644 index 0000000..706836a --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleController.java @@ -0,0 +1,159 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.StringKit; +import com.jeequan.jeepay.db.entity.SysRole; +import com.jeequan.jeepay.db.entity.SysUserRoleRela; +import com.jeequan.jeepay.service.impl.SysRoleEntRelaService; +import com.jeequan.jeepay.service.impl.SysRoleService; +import com.jeequan.jeepay.service.impl.SysUserRoleRelaService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * 角色管理类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/sysRoles") +public class SysRoleController extends CommonCtrl { + + @Autowired SysRoleService sysRoleService; + @Autowired SysUserRoleRelaService sysUserRoleRelaService; + @Autowired private AuthService authService; + @Autowired private SysRoleEntRelaService sysRoleEntRelaService; + + + /** list */ + @PreAuthorize("hasAnyAuthority( 'ENT_UR_ROLE_LIST', 'ENT_UR_USER_UPD_ROLE' )") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + SysRole queryObject = getObject(SysRole.class); + + LambdaQueryWrapper condition = SysRole.gw(); + condition.eq(SysRole::getSysType, CS.SYS_ROLE_TYPE.AGENT); + condition.eq(SysRole::getBelongInfoId, getCurrentAgentNo()); + + if(StringUtils.isNotEmpty(queryObject.getRoleName())){ + condition.like(SysRole::getRoleName, queryObject.getRoleName()); + } + + if(StringUtils.isNotEmpty(queryObject.getRoleId())){ + condition.like(SysRole::getRoleId, queryObject.getRoleId()); + } + + condition.orderByDesc(SysRole::getUpdatedAt); //时间倒序 + + IPage pages = sysRoleService.page(getIPage(true), condition); + return ApiRes.page(pages); + } + + + /** detail */ + @PreAuthorize("hasAuthority( 'ENT_UR_ROLE_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("recordId") String recordId) { + SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, recordId).eq(SysRole::getBelongInfoId, getCurrentAgentNo())); + if (sysRole == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + return ApiRes.ok(sysRole); + } + + /** add */ + @PreAuthorize("hasAuthority( 'ENT_UR_ROLE_ADD' )") + @RequestMapping(value="", method = RequestMethod.POST) + public ApiRes add() { + SysRole SysRole = getObject(SysRole.class); + String roleId = "ROLE_" + StringKit.getUUID(6); + SysRole.setRoleId(roleId); + SysRole.setSysType(CS.SYS_ROLE_TYPE.AGENT); //后台系统 + SysRole.setBelongInfoId(getCurrentUser().getSysUser().getBelongInfoId()); + sysRoleService.save(SysRole); + + //权限信息集合 + String entIdListStr = getValString("entIdListStr"); + + //如果包含: 可分配权限的权限 && entIdListStr 不为空 + if(getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_UR_ROLE_DIST")) + && StringUtils.isNotEmpty(entIdListStr)){ + List entIdList = JSONArray.parseArray(entIdListStr, String.class); + + sysRoleEntRelaService.resetRela(roleId, entIdList); + } + + return ApiRes.ok(); + } + + /** update */ + @PreAuthorize("hasAuthority( 'ENT_UR_ROLE_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.PUT) + public ApiRes update(@PathVariable("recordId") String recordId) { + + SysRole sysRole = getObject(SysRole.class); + + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(SysRole::getRoleId, recordId); + updateWrapper.eq(SysRole::getBelongInfoId, getCurrentAgentNo()); + sysRoleService.update(sysRole, updateWrapper); + + //权限信息集合 + String entIdListStr = getValString("entIdListStr"); + + //如果包含: 可分配权限的权限 && entIdListStr 不为空 + if(getCurrentUser().getAuthorities().contains(new SimpleGrantedAuthority("ENT_UR_ROLE_DIST")) + && StringUtils.isNotEmpty(entIdListStr)){ + List entIdList = JSONArray.parseArray(entIdListStr, String.class); + + sysRoleEntRelaService.resetRela(recordId, entIdList); + + List sysUserIdList = new ArrayList<>(); + sysUserRoleRelaService.list(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, recordId)).stream().forEach(item -> sysUserIdList.add(item.getUserId())); + + //查询到该角色的人员, 将redis更新 + authService.refAuthentication(sysUserIdList); + } + + return ApiRes.ok(); + } + + /** delete */ + @PreAuthorize("hasAuthority('ENT_UR_ROLE_DEL')") + @RequestMapping(value="/{recordId}", method = RequestMethod.DELETE) + public ApiRes del(@PathVariable("recordId") String recordId) { + SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, recordId).eq(SysRole::getBelongInfoId, getCurrentAgentNo())); + if (sysRole == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + if(sysUserRoleRelaService.count(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, recordId)) > 0){ + throw new BizException("当前角色已分配到用户, 不可删除!"); + } + sysRoleService.removeRole(recordId); + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleEntRelaController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleEntRelaController.java new file mode 100644 index 0000000..ed2021d --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysRoleEntRelaController.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.SysRole; +import com.jeequan.jeepay.db.entity.SysRoleEntRela; +import com.jeequan.jeepay.db.entity.SysUserRoleRela; +import com.jeequan.jeepay.service.impl.SysRoleEntRelaService; +import com.jeequan.jeepay.service.impl.SysRoleService; +import com.jeequan.jeepay.service.impl.SysUserRoleRelaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * 角色权限管理类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/sysRoleEntRelas") +public class SysRoleEntRelaController extends CommonCtrl { + + @Autowired private SysRoleEntRelaService sysRoleEntRelaService; + @Autowired private SysUserRoleRelaService sysUserRoleRelaService; + @Autowired private SysRoleService sysRoleService; + @Autowired private AuthService authService; + + /** list */ + @PreAuthorize("hasAuthority( 'ENT_UR_ROLE_DIST' )") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + SysRoleEntRela queryObject = getObject(SysRoleEntRela.class); + + LambdaQueryWrapper condition = SysRoleEntRela.gw(); + + if(queryObject.getRoleId() != null){ + condition.eq(SysRoleEntRela::getRoleId, queryObject.getRoleId()); + } + + IPage pages = sysRoleEntRelaService.page(getIPage(true), condition); + + return ApiRes.page(pages); + } + + /** 重置角色权限关联信息 */ + @PreAuthorize("hasAuthority( 'ENT_UR_ROLE_DIST' )") + @RequestMapping(value="relas/{roleId}", method = RequestMethod.POST) + public ApiRes relas(@PathVariable("roleId") String roleId) { + + SysRole sysRole = sysRoleService.getOne(SysRole.gw().eq(SysRole::getRoleId, roleId).eq(SysRole::getBelongInfoId, getCurrentAgentNo())); + if (sysRole == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + List entIdList = JSONArray.parseArray(getValStringRequired("entIdListStr"), String.class); + + sysRoleEntRelaService.resetRela(roleId, entIdList); + + List sysUserIdList = new ArrayList<>(); + sysUserRoleRelaService.list(SysUserRoleRela.gw().eq(SysUserRoleRela::getRoleId, roleId)).stream().forEach(item -> sysUserIdList.add(item.getUserId())); + + //查询到该角色的人员, 将redis更新 + authService.refAuthentication(sysUserIdList); + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserController.java new file mode 100644 index 0000000..e62d282 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserController.java @@ -0,0 +1,327 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import cn.hutool.core.util.DesensitizedUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.bizcommons.manage.sms.SmsManager; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.SysUserAuth; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.db.entity.SysUserTeam; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.List; + +/** + * 用户管理类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/sysUsers") +public class SysUserController extends CommonCtrl { + + @Autowired SysUserService sysUserService; + @Autowired SysUserAuthService sysUserAuthService; + @Autowired SysConfigService sysConfigService; + @Autowired private AuthService authService; + @Autowired private SysUserTeamService sysUserTeamService; + @Autowired private AgentInfoService agentInfoService; + @Autowired private SmsManager smsManager; + + + /** list */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_LIST' )") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + SysUserEntity queryObject = getObject(SysUserEntity.class); + queryObject.setSysType(CS.SYS_ROLE_TYPE.AGENT); + queryObject.setBelongInfoId(getCurrentAgentNo()); + + // 是否app登录 + String loginType = getCurrentUser().getLoginType(); + boolean isApp = StringUtils.isNotBlank(loginType) && (loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE)); + + // true表示是APP端 + if (isApp) { + String queryNameOrPhone = getValString("queryNameOrPhone"); // 名字或手机号模糊查询 + LambdaQueryWrapper queryWrapper = SysUserEntity.gw(); + queryWrapper.eq(SysUserEntity::getSysType, queryObject.getSysType()); + queryWrapper.eq(SysUserEntity::getBelongInfoId, queryObject.getBelongInfoId()); + queryWrapper.eq(null != queryObject.getUserType(), SysUserEntity::getUserType, queryObject.getUserType()); + + if (StringUtils.isNotBlank(queryNameOrPhone)) { + queryWrapper.and(wr -> { + wr.like(SysUserEntity::getRealname, queryNameOrPhone) + .or().like(SysUserEntity::getTelphone, queryNameOrPhone); + }); + } + + IPage iPage = sysUserService.page(getIPage(), queryWrapper); + // 数据脱敏 + iPage.getRecords().stream().forEach(i -> i.setTelphone(DesensitizedUtil.mobilePhone(i.getTelphone()))); + return ApiRes.page(iPage); + } + + + long count = sysUserService.queryCount(queryObject); + if (count <=0 ) { + return ApiRes.page(new Page()); + } + + List list = sysUserService.selectList(getIPage(), queryObject); + + // 邀请码二维码地址 + String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl()); + String agentRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getAgentSiteUrl()); + list.forEach(item -> { + item.put("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, item.getString("inviteCode"))); + item.put("agentInviteCodeUrl", String.format("%s?c=%s", agentRegisterUrl, item.getString("inviteCode"))); + + // 数据脱敏 + item.put("telphone", DesensitizedUtil.mobilePhone(item.getString("telphone"))); + // 是否初始用户 + boolean ifInitUser = agentInfoService.count(AgentInfo.gw().eq(AgentInfo::getInitUserId, item.getLong("sysUserId")).eq(AgentInfo::getAgentNo, item.getString("belongInfoId"))) >0; + item.put("initUser", ifInitUser); + }); + + return ApiRes.page(getIPage(), list, count); + } + + + /** detail */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_VIEW' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("recordId") Integer recordId) { + + SysUserEntity sysUserEntity = sysUserService.getById(recordId); + if (sysUserEntity == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + if (!sysUserEntity.getBelongInfoId().equals(getCurrentUser().getSysUser().getBelongInfoId())) { + throw new BizException(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + + if (sysUserEntity.getTeamId() != null) { + SysUserTeam sysUserTeam = sysUserTeamService.getById(sysUserEntity.getTeamId()); + if (sysUserTeam != null) { + sysUserEntity.addExt("teamName", sysUserTeam.getTeamName()); + } + } + + return ApiRes.ok(sysUserEntity); + } + + /** add */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_ADD' )") + @RequestMapping(value="", method = RequestMethod.POST) + @MethodLog(remark = "添加管理员") + public ApiRes add() { + String loginPassword = getValString("loginPassword"); + Byte isNotify = getValByteRequired("isNotify"); + if (StringUtils.isBlank(loginPassword)) { + loginPassword = null; + } + SysUserEntity sysUserEntity = getObject(SysUserEntity.class); + sysUserEntity.setBelongInfoId(getCurrentUser().getSysUser().getBelongInfoId()); + + sysUserService.addSysUser(sysUserEntity, CS.SYS_ROLE_TYPE.AGENT, loginPassword); + + // 发送短信通知 + if (isNotify == CS.YES) { + smsManager.sendDiyContentSms(SmsBizDiyContentModel.genUserOpenAccount(sysUserEntity.getTelphone(), sysUserEntity.getLoginUsername(), loginPassword )); + } + + return ApiRes.ok(); + } + + + /** 修改操作员 登录认证信息 */ +// @RequestMapping(value="/modifyPwd", method = RequestMethod.PUT) + public ApiRes authInfo() { + + Long opSysUserId = getValLongRequired("recordId"); //操作员ID + + //更改密码, 验证当前用户信息 + String currentUserPwd = getValStringRequired("originalPwd"); //当前用户登录密码 + //验证当前密码是否正确 + if(!sysUserAuthService.validateCurrentUserPwd(currentUserPwd)){ + throw new BizException("原密码验证失败!"); + } + + String opUserPwd = getValStringRequired("confirmPwd"); + + // 验证原密码与新密码是否相同 + if (opUserPwd.equals(currentUserPwd)) { + throw new BizException("新密码与原密码相同!"); + } + + sysUserAuthService.resetAuthInfo(opSysUserId, null, null, true, opUserPwd, CS.SYS_ROLE_TYPE.AGENT); + return ApiRes.ok(); + } + + + /** update */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.PUT) + @MethodLog(remark = "修改操作员信息") + public ApiRes update(@PathVariable("recordId") Long recordId) { + + SysUserEntity sysUserEntity = getObject(SysUserEntity.class); + sysUserEntity.setSysUserId(recordId); + + // 避免越权操作 + SysUserEntity dbRecord = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getSysUserId, recordId) + .eq(SysUserEntity::getSysType, CS.SYS_ROLE_TYPE.AGENT).eq(SysUserEntity::getBelongInfoId, getCurrentAgentNo())); + if (dbRecord == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + boolean delAuthenticationFlag = sysUserService.updateUserOnTx(sysUserEntity, recordId, getCurrentUser().getSysUserId()); + + // 删除用户redis缓存信息 + if(delAuthenticationFlag){ + authService.delAuthentication(Arrays.asList(recordId)); + } + + // 返回最新用户信息 + SysUserEntity latestRecord = sysUserService.getById(recordId); + // 邀请码二维码地址 + String mchRegisterUrl = String.format("%s/register", sysConfigService.getDBApplicationConfig().getMchSiteUrl()); + latestRecord.addExt("inviteCodeUrl", String.format("%s?c=%s", mchRegisterUrl, latestRecord.getInviteCode())); + + return ApiRes.ok(latestRecord); + } + + /** delete */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_DELETE' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.DELETE) + @MethodLog(remark = "删除操作员信息") + public ApiRes delete(@PathVariable("recordId") Long recordId) { + //查询该操作员信息 + SysUserEntity sysUserEntity = sysUserService.getById(recordId); + if (sysUserEntity == null) { + throw new BizException("该操作员不存在!"); + } + + //判断是否自己删除自己 + if(recordId.equals(getCurrentUser().getSysUser().getSysUserId())){ + throw new BizException("系统不允许删除当前登陆用户!"); + } + + //判断是否删除商户默认超管 + if(agentInfoService.count(AgentInfo.gw().eq(AgentInfo::getInitUserId, recordId).eq(AgentInfo::getAgentNo, sysUserEntity.getBelongInfoId())) > 0 ){ + throw new BizException("系统不允许删除服务商默认用户!"); + } + + // 删除用户 + sysUserService.removeUser(sysUserEntity, CS.SYS_ROLE_TYPE.AGENT); + + //如果用户被删除,需要更新redis数据 + authService.refAuthentication(Arrays.asList(recordId)); + + return ApiRes.ok(); + } + + /** MFA验证 解绑 */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_MFA_DELETE' )") + @RequestMapping(value="/mfaRelieve", method = RequestMethod.PUT) + @MethodLog(remark = "MFA验证解除") + public ApiRes mfaRelieve() throws BizException{ + Long recordId = getValLongRequired("recordId"); + // 当前登录账户是否为超管 + Long currentUserId = getCurrentUser().getSysUser().getSysUserId(); + // 解除操作员MFA验证 + sysUserService.relieveOperatorMFA(currentUserId, recordId); + return ApiRes.ok(); + } + + /** 解除登录失败次数限制 */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_LOGIN_LIMIT_DELETE' )") + @RequestMapping(value="/loginLimit/{recordId}", method = RequestMethod.DELETE) + @MethodLog(remark = "解除登录限制") + public ApiRes deleteLoginLimit(@PathVariable("recordId") Long recordId) throws BizException{ + + List authList = sysUserAuthService.list(SysUserAuth.gw().eq(SysUserAuth::getUserId, recordId)); + if (authList.isEmpty()) { + return ApiRes.ok(); + } + + for (SysUserAuth sysUserAuth : authList) { + + RedisUtil.del(CS.getCacheKeyLoginErr(CS.SYS_ROLE_TYPE.AGENT, sysUserAuth.getIdentifier())); + + } + + return ApiRes.ok(); + } + + /** 提交审核 */ + @RequestMapping(value="/audit", method = RequestMethod.PUT) + @MethodLog(remark = "提交审核") + public ApiRes audit() throws BizException{ + + // 提交的资料 + AgentInfo agentInfo = getObject(AgentInfo.class); + // 查询数据库中的服务商信息 + AgentInfo dbAgentInfo = agentInfoService.getById(getCurrentAgentNo()); + if (dbAgentInfo == null) { + throw new BizException("服务商信息不存在!"); + } + + if (dbAgentInfo.getState() == CS.YES) { + throw new BizException("当前服务商已通过审核,不可修改信息!"); + } + + // 更新服务商资料 + AgentInfo updateInfo = new AgentInfo(); + updateInfo.setAgentNo(dbAgentInfo.getAgentNo()); + updateInfo.setState(AgentInfo.AUDIT_STATE_ING); + + updateInfo.setAgentName(agentInfo.getAgentName()); // 服务商名称 + updateInfo.setAgentShortName(agentInfo.getAgentShortName()); // 服务商简称 + updateInfo.setContactName(agentInfo.getContactName()); // 联系人姓名 + updateInfo.setContactEmail(agentInfo.getContactEmail()); // 联系人邮箱 + updateInfo.setLicenseImg(agentInfo.getLicenseImg()); // 营业执照 + updateInfo.setIdcard1Img(agentInfo.getIdcard1Img()); // 身份证人像面 + updateInfo.setIdcard2Img(agentInfo.getIdcard2Img()); // 身份证国徽面 + updateInfo.setIdcardInHandImg(agentInfo.getIdcardInHandImg()); // 手持身份证照 + updateInfo.setBankCardImg(agentInfo.getBankCardImg()); // 银行卡照片 + updateInfo.setPermitImg(agentInfo.getPermitImg()); // 许可证照片 + updateInfo.setAgentType(agentInfo.getAgentType()); // 服务商类型 + updateInfo.setSettAccountType(agentInfo.getSettAccountType()); // 账户类型 + updateInfo.setSettAccountNo(agentInfo.getSettAccountNo()); // 账户账号 + updateInfo.setSettAccountName(agentInfo.getSettAccountName()); // 账户姓名 + updateInfo.setSettAccountBank(agentInfo.getSettAccountBank()); // 银行名称 + updateInfo.setSettAccountSubBank(agentInfo.getSettAccountSubBank()); // 开户行支行名称 + + agentInfoService.updateById(updateInfo); + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserRoleRelaController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserRoleRelaController.java new file mode 100644 index 0000000..1f8f4ac --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserRoleRelaController.java @@ -0,0 +1,78 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.db.entity.SysUserRoleRela; +import com.jeequan.jeepay.service.impl.SysUserRoleRelaService; +import com.jeequan.jeepay.service.impl.SysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.List; + +/** + * 用户角色管理类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@RestController +@RequestMapping("api/sysUserRoleRelas") +public class SysUserRoleRelaController extends CommonCtrl { + + @Autowired private SysUserRoleRelaService sysUserRoleRelaService; + @Autowired private SysUserService sysUserService; + @Autowired private AuthService authService; + + /** list */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_UPD_ROLE' )") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + SysUserRoleRela queryObject = getObject(SysUserRoleRela.class); + + LambdaQueryWrapper condition = SysUserRoleRela.gw(); + + if(queryObject.getUserId() != null){ + condition.eq(SysUserRoleRela::getUserId, queryObject.getUserId()); + } + + IPage pages = sysUserRoleRelaService.page(getIPage(true), condition); + + return ApiRes.page(pages); + } + + /** 重置用户角色关联信息 */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_UPD_ROLE' )") + @RequestMapping(value="relas/{sysUserId}", method = RequestMethod.POST) + public ApiRes relas(@PathVariable("sysUserId") Long sysUserId) { + SysUserEntity dbRecord = sysUserService.getOne(SysUserEntity.gw().eq(SysUserEntity::getSysUserId, sysUserId).eq(SysUserEntity::getBelongInfoId, getCurrentAgentNo())); + if (dbRecord == null) { + throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + List roleIdList = JSONArray.parseArray(getValStringRequired("roleIdListStr"), String.class); + + sysUserService.saveUserRole(sysUserId, roleIdList); + + authService.refAuthentication(Arrays.asList(sysUserId)); + + return ApiRes.ok(); + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserTeamController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserTeamController.java new file mode 100644 index 0000000..59d2a88 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/sysuser/SysUserTeamController.java @@ -0,0 +1,232 @@ +package com.jeequan.jeepay.agent.ctrl.sysuser; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.aop.MethodLog; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.db.entity.SysUserTeam; +import com.jeequan.jeepay.service.impl.SysUserService; +import com.jeequan.jeepay.service.impl.SysUserTeamService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +/** +* 操作员列表 +* +* @author zx +* +* @date 2022/3/17 17:13 +*/ +@RestController +@RequestMapping("/api/userTeams") +public class SysUserTeamController extends CommonCtrl { + + @Autowired private SysUserTeamService sysUserTeamService; + @Autowired private SysUserService sysUserService; + + /** list */ + @PreAuthorize("hasAuthority( 'ENT_UR_TEAM_LIST' )") + @RequestMapping(value="", method = RequestMethod.GET) + public ApiRes list() { + + // 是否app登录 + String loginType = getCurrentUser().getLoginType(); + boolean isApp = StringUtils.isNotBlank(loginType) && (loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.APP) || loginType.equals(JWTPayload.LOGIN_PAGE_TYPE.LITE)); + + SysUserTeam queryObject = getObject(SysUserTeam.class); + queryObject.setSysType(CS.SYS_ROLE_TYPE.AGENT); + queryObject.setBelongInfoId(getCurrentAgentNo()); + + // 团队列表 + IPage iPage = sysUserTeamService.selectPage(getIPage(true), queryObject); + + // 1、查询全部团队列表,直接返回 + int pageSize = getValIntegerRequired("pageSize"); + if (pageSize == -1) { + return ApiRes.page(iPage); + } + + // 2、web端,仅返回团队列表 + if (!isApp) { + return ApiRes.page(iPage); + } + + if (iPage.getTotal() <= 0) { + return ApiRes.page(new Page()); + } + + // 3、app端,返回团队列表 包含团队成员信息 + // 当前分页团队ID集合 + List teamIdList = new LinkedList<>(); + iPage.getRecords().forEach(record -> teamIdList.add(record.getTeamId())); + + // 查询团队id下的用户 + List list = sysUserTeamService.selectList(teamIdList, null, null); + if (CollUtil.isEmpty(list)) { + return ApiRes.page(iPage); + } + + // 外层:循环团队 内层:团队成员数据 + for (SysUserTeam sysUserTeam : iPage.getRecords()) { + + // 用户列表 + List userList = new LinkedList<>(); + + // 团队总商户数 + Long totalMchCount = 0L; + + // 团队总交易额 + Long totalOrderAmount = 0L; + + for (JSONObject json : list) { + if (sysUserTeam.getTeamId().equals(json.getLong("teamId"))) { + + userList.add(json); + + if (json.getLong("mchCount") != null) { + totalMchCount += json.getLong("mchCount"); + } + + if (json.getLong("orderAmount") != null) { + totalOrderAmount += json.getLong("orderAmount"); + } + } + } + + sysUserTeam.addExt("userList", userList); + sysUserTeam.addExt("totalMchCount", totalMchCount); + sysUserTeam.addExt("totalOrderAmount", totalOrderAmount); + } + + return ApiRes.page(iPage); + } + + /** web端 团队详情下的拓展员信息 */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_VIEW' )") + @RequestMapping(value="/userList/{recordId}", method = RequestMethod.GET) + public ApiRes userList(@PathVariable("recordId") Long recordId) { + + IPage iPage = sysUserService.page(getIPage(), SysUserEntity.gw().eq(SysUserEntity::getTeamId, recordId)); + if (iPage.getTotal() <= 0) { + return ApiRes.page(new Page()); + } + + // 查询团队id下的用户 + String dateRange = getValStringRequired("queryDateRange"); + // 获取查询时间请求参数 [开始时间, 结束时间] + Date[] queryDateRangeArray = DateKit.getQueryDateRange(dateRange); + + String createdStart = DateUtil.formatDateTime(queryDateRangeArray[0]); + String createdEnd = DateUtil.formatDateTime(queryDateRangeArray[1]); + + + List list = sysUserTeamService.selectList(Arrays.asList(recordId), createdStart, createdEnd); + if (CollUtil.isEmpty(list)) { + return ApiRes.page(iPage); + } + + // 用户列表 + List userList = new LinkedList<>(); + + for (SysUserEntity sysUserEntity : iPage.getRecords()) { + for (JSONObject json : list) { + if (sysUserEntity.getSysUserId().equals(json.getLong("sysUserId"))) { + userList.add(json); + } + } + } + + return ApiRes.page(getIPage(), userList, iPage.getTotal()); + } + + + /** detail */ + @PreAuthorize("hasAuthority( 'ENT_UR_USER_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.GET) + public ApiRes detail(@PathVariable("recordId") Integer recordId) { + return ApiRes.ok(sysUserTeamService.getById(recordId)); + } + + /** add */ + @PreAuthorize("hasAuthority( 'ENT_UR_TEAM_ADD' )") + @MethodLog(remark = "添加团队") + @RequestMapping(value="", method = RequestMethod.POST) + public ApiRes add() { + SysUserTeam sysUserTeam = getObject(SysUserTeam.class); + sysUserTeam.setSysType(CS.SYS_ROLE_TYPE.AGENT); + sysUserTeam.setBelongInfoId(getCurrentAgentNo()); + + long count = sysUserTeamService.count(SysUserTeam.gw().eq(SysUserTeam::getTeamName, sysUserTeam.getTeamName())); + if (count > 0) { + throw new BizException("团队名已存在"); + } + + boolean result = sysUserTeamService.save(sysUserTeam); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_CREATE); + } + + return ApiRes.ok(); + } + + + /** update */ + @PreAuthorize("hasAuthority( 'ENT_UR_TEAM_EDIT' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.PUT) + @MethodLog(remark = "修改团队信息") + public ApiRes update(@PathVariable("recordId") Long recordId) { + SysUserTeam sysUserTeam = getObject(SysUserTeam.class); + sysUserTeam.setTeamId(recordId); + + long count = sysUserTeamService.count(SysUserTeam.gw() + .eq(SysUserTeam::getTeamName, sysUserTeam.getTeamName()) + .ne(SysUserTeam::getTeamId, recordId) + ); + if (count > 0) { + throw new BizException("团队名已存在"); + } + + boolean result = sysUserTeamService.updateById(sysUserTeam); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_UPDATE); + } + + return ApiRes.ok(); + } + + /** delete */ + @PreAuthorize("hasAuthority( 'ENT_UR_TEAM_DELETE' )") + @RequestMapping(value="/{recordId}", method = RequestMethod.DELETE) + @MethodLog(remark = "删除团队") + public ApiRes delete(@PathVariable("recordId") Long recordId) { + + // 删除团队 + boolean result = sysUserTeamService.removeById(recordId); + if (!result) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_DELETE); + } + + return ApiRes.ok(); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/ChannelUserIdNotifyController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/ChannelUserIdNotifyController.java new file mode 100644 index 0000000..526a636 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/ChannelUserIdNotifyController.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.agent.ctrl.transfer; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.agent.websocket.server.WsChannelUserIdServer; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +/** +* 获取用户ID - 回调函数 +* +* @author terrfly +* +* @date 2021/8/13 17:54 +*/ +@Controller +@RequestMapping("/api/anon/channelUserIdCallback") +public class ChannelUserIdNotifyController extends CommonCtrl { + + @RequestMapping("") + public String channelUserIdCallback() { + + try { + //请求参数 + JSONObject params = getReqParamJSON(); + + String extParam = params.getString("extParam"); + String channelUserId = params.getString("channelUserId"); + String appId = params.getString("appId"); + + //推送到前端 + WsChannelUserIdServer.sendMsgByAppAndCid(appId, extParam, channelUserId); + + } catch (Exception e) { + request.setAttribute("errMsg", e.getMessage()); + } + + return "channelUser/getChannelUserIdPage"; + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/TransferConfigController.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/TransferConfigController.java new file mode 100644 index 0000000..76295ca --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/ctrl/transfer/TransferConfigController.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.agent.ctrl.transfer; + +import cn.hutool.core.util.ObjUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.agent.ctrl.CommonCtrl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.IsvUserConn; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.RateConfig; +import com.jeequan.jeepay.db.entity.TransferInterfaceDefineEntity; +import com.jeequan.jeepay.service.impl.IsvInfoService; +import com.jeequan.jeepay.service.impl.TransferInterfaceDefineService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * TODO + * + * @author deng + * @since 2024/4/25 + */ +@RestController +@RequestMapping("api/transferConfig") +public class TransferConfigController extends CommonCtrl { + + @Autowired + private TransferInterfaceDefineService transferInterfaceDefineService; + + @Autowired + private IsvInfoService isvInfoService; + + /** + * 查询可用的支付接口 + *

+ * 使用功能项目: 参数及费率的填写 + * 服务商查询全部支付接口 + * 服务商查询服务商开启的支付接口 + **/ + @GetMapping("/ifCodes") + public ApiRes ifCodes() { + + // 搜索条件 + String ifName = getValString("ifName"); + + String infoId = getValStringRequired("infoId"); // infoId + String configMode = getValStringRequired("configMode"); // 设置类型 + + // 支付接口列表 + LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); + lambdaQueryWrapper.eq(TransferInterfaceDefineEntity::getState, CS.YES); // 查询可用的支付接口列表 + + lambdaQueryWrapper.like(ObjUtil.isNotEmpty(ifName), TransferInterfaceDefineEntity::getTransIfName, ifName); + + AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo()); + + Map ifCodeMap = new HashMap<>(); + + // 服务商 配置 商户费率 | 下级服务商费率 | 自己配置信息 【显示 当前服务商所有接口】 + if (RateConfig.CONFIG_MODE_AGENTEMCH.equals(configMode) || + RateConfig.CONFIG_MODE_AGENTSUBAGENT.equals(configMode) || + RateConfig.CONFIG_MODE_AGENTSELF.equals(configMode) + ) { + + ifCodeMap = isvInfoService.getTransIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), CS.YES); + List ifCodeList = new ArrayList<>(ifCodeMap.keySet()); + + if (ifCodeList.isEmpty()) { // 没有可用的接口 + return ApiRes.ok(ifCodeList); + } + lambdaQueryWrapper.in(TransferInterfaceDefineEntity::getTransIfCode, ifCodeList); + + } else if (RateConfig.CONFIG_MODE_AGENTAPPLYMENT.equals(configMode)) { // 服务商进件 + // 查询 当前服务商 开通的 + ifCodeMap = isvInfoService.getTransIsvUserConn(CS.SYS_ROLE_TYPE.AGENT, agentInfo.getAgentNo(), null); + + if (ifCodeMap.isEmpty()) { // 没有可用的接口 + return ApiRes.ok(Collections.emptyList()); + } + + lambdaQueryWrapper.in(TransferInterfaceDefineEntity::getTransIfCode, ifCodeMap.keySet()); + } + + + final List list = new ArrayList<>(); + lambdaQueryWrapper.orderByAsc(TransferInterfaceDefineEntity::getId); + final Map finalMap = ifCodeMap; + transferInterfaceDefineService.list(lambdaQueryWrapper).forEach(item -> { + // 如果服务商上级配置的开启进件为关闭,那么最终展示的列表中显示的是否开启进件也为关闭 + IsvUserConn ifCodeInfo = finalMap.get(item.getTransIfCode()); + boolean isEnabled = ifCodeInfo.getStatus() == CS.YES && ifCodeInfo.getConfigStatus() == CS.YES; + item.addExt("configState", ifCodeInfo.getStatus()); + + item.setState(isEnabled ? CS.YES : CS.NO); + list.add(item); + }); + + return ApiRes.ok(list); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/CleanAgentLoginAuthCacheMQReceiver.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/CleanAgentLoginAuthCacheMQReceiver.java new file mode 100644 index 0000000..e458b13 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/CleanAgentLoginAuthCacheMQReceiver.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.agent.mq; + +import com.jeequan.jeepay.components.mq.model.CleanAgentLoginAuthCacheMQ; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; + +/** +* 接收MQ消息 +* 业务: 清除服务商的登录信息 +* @author terrfly +* @date 2021/7/27 9:23 +*/ +@Slf4j +@Component +public class CleanAgentLoginAuthCacheMQReceiver implements CleanAgentLoginAuthCacheMQ.IMQReceiver { + + @Override + public void receive(CleanAgentLoginAuthCacheMQ.MsgPayload payload) { + + log.info("成功接收删除商户用户登录的订阅通知, msg={}", payload); + + if (CleanAgentLoginAuthCacheMQ.CLEAN_CACHE_TYPE_LOGIN_TOKEN.equals(payload.getCleanCacheType())) { + + // 字符串转List + List userIdList = payload.getList(); + // 删除redis用户缓存 + if(userIdList == null || userIdList.isEmpty()){ + log.info("用户ID为空"); + return ; + } + for (String sysUserId : userIdList) { + Collection cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(Long.valueOf(sysUserId), "*")); + if(cacheKeyList == null || cacheKeyList.isEmpty()){ + continue; + } + for (String cacheKey : cacheKeyList) { + // 删除用户Redis信息 + RedisUtil.del(cacheKey); + continue; + } + } + log.info("无权限登录用户信息已清除"); + } + + // 清除登录失败次数限制缓存 + else if (CleanAgentLoginAuthCacheMQ.CLEAN_CACHE_TYPE_LOGIN_ERR.equals(payload.getCleanCacheType())) { + + // 字符串转List + List list = payload.getList(); + + // 删除redis用户缓存 + if(CollectionUtils.isEmpty(list)){ + log.info("登录用户名list为空"); + return ; + } + for (String loginUserName : list) { + RedisUtil.del(CS.getCacheKeyLoginErr(CS.SYS_ROLE_TYPE.AGENT, loginUserName)); + } + + log.info("登录限制已清除"); + } + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetAppConfigMQReceiver.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetAppConfigMQReceiver.java new file mode 100644 index 0000000..b94fc50 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetAppConfigMQReceiver.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.agent.mq; + +import com.jeequan.jeepay.components.mq.model.ResetAppConfigMQ; +import com.jeequan.jeepay.core.interfaces.push.IBaiduBceService; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.service.impl.SysConfigService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 接收MQ消息 + * 业务: 更新系统配置参数 + * @author terrfly + * @date 2021/7/27 9:23 + */ +@Slf4j +@Component +public class ResetAppConfigMQReceiver implements ResetAppConfigMQ.IMQReceiver { + + @Autowired + private SysConfigService sysConfigService; + + @Override + public void receive(ResetAppConfigMQ.MsgPayload payload) { + + log.info("成功接收更新系统配置的订阅通知, msg={}", payload); + sysConfigService.initDBConfig(payload.getGroupKey()); + + // 修改百度语音配置需清空redis缓存的百度token + if (SysConfigService.BAIDU_BCE_CONFIG.getLeft().equals(payload.getGroupKey())) { + IBaiduBceService baiduBceService = SpringBeansUtil.getBean("baiduBceService", IBaiduBceService.class); + baiduBceService.clearBaiduBceTokenCache(SysConfigService.BAIDU_BCE_CONFIG.getRight()); + } + log.info("系统配置静态属性已重置"); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetIsvMchAppInfoMQReceiver.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetIsvMchAppInfoMQReceiver.java new file mode 100644 index 0000000..bf0d114 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/mq/ResetIsvMchAppInfoMQReceiver.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.agent.mq; + +import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ; +import com.jeequan.jeepay.core.interfaces.IConfigContextService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 接收MQ消息 + * 业务: 更新服务商/商户/商户应用配置信息; + * + * @author terrfly + * @date 2021/7/27 9:23 + */ +@Slf4j +@Component +public class ResetIsvMchAppInfoMQReceiver implements ResetIsvMchAppInfoConfigMQ.IMQReceiver { + + @Autowired(required = false) + private IConfigContextService configContextService; + + @Override + public void receive(ResetIsvMchAppInfoConfigMQ.MsgPayload payload) { + + if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_ISV_INFO) { + this.modifyIsvInfo(payload.getIsvNo()); + } else if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO) { + this.modifyMchInfo(payload.getMchNo()); + } + + } + + /** + * 接收 [商户配置信息] 的消息 + */ + private void modifyMchInfo(String mchNo) { + log.info("成功接收 [商户配置信息] 的消息, msg={}", mchNo); + if (configContextService != null) configContextService.initMchInfoConfigContext(mchNo); + log.info(" [商户配置信息] 已重置"); + } + + /** + * 接收 [商户应用支付参数配置信息] 的消息 + */ + private void modifyMchApp(String mchNo, String appId) { + log.info("成功接收 [商户应用支付参数配置信息] 的消息, mchNo={}, appId={}", mchNo, appId); + if (configContextService != null) configContextService.initMchAppConfigContext(mchNo, appId); + log.info(" [商户应用支付参数配置信息] 已重置"); + } + + /** + * 重置ISV信息 + */ + private void modifyIsvInfo(String isvNo) { + log.info("成功接收 [ISV信息] 重置, msg={}", isvNo); + if (configContextService != null) configContextService.initIsvConfigContext(isvNo); + log.info("[ISV信息] 已重置"); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationEntryPoint.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationEntryPoint.java new file mode 100644 index 0000000..f3b7590 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationEntryPoint.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.agent.secruity; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Serializable; + +/* + * 用户身份认证失败处理类 + * + * @author terrfly + * + * @date 2021/6/8 17:11 + */ +@Component +public class JeeAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // This is invoked when user tries to access a secured REST resource without supplying any credentials + // We should just send a 401 Unauthorized response because there is no 'login page' to redirect to + + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + + //返回json形式的错误信息 +// response.setCharacterEncoding("UTF-8"); +// response.setContentType("application/json"); +// response.getWriter().println("{\"code\":1001, \"msg\":\"Unauthorized\"}"); + response.getWriter().flush(); + + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationTokenFilter.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationTokenFilter.java new file mode 100644 index 0000000..68b9653 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeAuthenticationTokenFilter.java @@ -0,0 +1,107 @@ +package com.jeequan.jeepay.agent.secruity; + +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import com.jeequan.jeepay.agent.service.AuthService; +import com.jeequan.jeepay.bizcommons.manage.auth.AuthManage; +import com.jeequan.jeepay.core.cache.ITokenService; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.jwt.JWTUtils; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + *

Title: JwtAuthenticationTokenFilter.java + *

Description: + * spring security框架中验证组件的前置过滤器; + * 用于验证token有效期,并放置ContextAuthentication信息,为后续spring security框架验证提供数据; + * 避免使用@Component等bean自动装配注解:@Component会将filter被spring实例化为web容器的全局filter,导致重复过滤。 + * @modify terrfly + * @version V1.0 + * + * @date 2021-04-27 15:50 + *

+ */ +public class JeeAuthenticationTokenFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + + JeeUserDetails jeeUserDetails = commonFilter(request); + + if(jeeUserDetails == null){ + chain.doFilter(request, response); + return; + } + + // 密码是否过期 + if(AuthManage.passwordExpiredFilter(jeeUserDetails, request, response)){ + return ; + } + + // 服务商是否过审 + if(AuthManage.agentUnAuditFilter(jeeUserDetails, request, response)){ + return ; + } + + //将信息放置到Spring-security context中 + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jeeUserDetails, null, jeeUserDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + chain.doFilter(request, response); + } + + + private JeeUserDetails commonFilter(HttpServletRequest request){ + + + String authToken = request.getHeader(CS.ACCESS_TOKEN_NAME); + if(StringUtils.isEmpty(authToken)){ + authToken = request.getParameter(CS.ACCESS_TOKEN_NAME); + } + if(StringUtils.isEmpty(authToken)){ + return null; //放行,并交给UsernamePasswordAuthenticationFilter进行验证,返回公共错误信息. + } + + JWTPayload jwtPayload = JWTUtils.parseToken(authToken, SpringBeansUtil.getBean(SystemYmlConfig.class).getJwtSecret()); //反解析token信息 + //token字符串解析失败 + if( jwtPayload == null || StringUtils.isEmpty(jwtPayload.getCacheKey())) { + return null; + } + + //根据用户名查找数据库 + JeeUserDetails jwtBaseUser = RedisUtil.getObject(jwtPayload.getCacheKey(), JeeUserDetails.class); + if(jwtBaseUser == null){ // 找不到对应的缓存 + + // app登录 有效期30天, 超时自动续期 + if(jwtPayload.isAppLogin() && DateKit.currentTimeMillis() - jwtPayload.getCreated() <= (CS.TOKEN_TIME_APP * 1000) ){ + SpringBeansUtil.getBean(AuthService.class).authBySysUserId(jwtPayload.getSysUserId(), jwtPayload.getLoginType(), jwtPayload.getCacheKey()); + return RedisUtil.getObject(jwtPayload.getCacheKey(), JeeUserDetails.class); + } + + // 其他情况,需要删除 + RedisUtil.del(jwtPayload.getCacheKey()); + return null; //数据库查询失败,删除redis + } + + //续签时间 + RedisUtil.expire(jwtPayload.getCacheKey(), ITokenService.getTokenCacheTime(jwtPayload.getLoginType())); + + return jwtBaseUser; + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeUserDetailsServiceImpl.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeUserDetailsServiceImpl.java new file mode 100644 index 0000000..f1e218f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/JeeUserDetailsServiceImpl.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.agent.secruity; + +import com.jeequan.jeepay.converter.BaseConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.JeepayAuthenticationException; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.RegKit; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.SysUserAuth; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.service.impl.AgentInfoService; +import com.jeequan.jeepay.service.impl.SysUserAuthService; +import com.jeequan.jeepay.service.impl.SysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * UserDetailsService实现类 + * + * @author terrfly + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@Service +public class JeeUserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private SysUserService sysUserService; + + @Autowired + private SysUserAuthService sysUserAuthService; + + @Autowired AgentInfoService agentInfoService; + + @Autowired private BaseConverter baseConverter; + + /** + * + * 此函数为: authenticationManager.authenticate(upToken) 内部调用 ; + * 需返回 用户信息载体 / 用户密码 。 + * 用户角色+权限的封装集合 (暂时不查询, 在验证通过后再次查询,避免用户名密码输入有误导致查询资源浪费) + * + * **/ + @Override + public UserDetails loadUserByUsername(String loginUsernameStr) throws UsernameNotFoundException { + + //登录方式, 默认为账号密码登录 + byte identityType = CS.AUTH_TYPE.LOGIN_USER_NAME; + if(RegKit.isMobile(loginUsernameStr)){ + identityType = CS.AUTH_TYPE.TELPHONE; //手机号登录 + } + + //首先根据登录类型 + 用户名得到 信息 + SysUserAuth auth = sysUserAuthService.selectByLogin(loginUsernameStr, identityType, CS.SYS_ROLE_TYPE.AGENT); +// SysUserAuth auth = sysUserAuthService.getUserByLogin(loginUsernameStr, identityType); + + if(auth == null){ //没有该用户信息 + throw JeepayAuthenticationException.build("用户名/密码错误!"); + } + + //用户ID + Long userId = auth.getUserId(); + + SysUserEntity sysUserEntity = sysUserService.getById(userId); + + if (sysUserEntity == null) { + throw JeepayAuthenticationException.build("用户名/密码错误!"); + } + + if(CS.PUB_USABLE != sysUserEntity.getState()){ //状态不合法 + throw JeepayAuthenticationException.build("用户状态不可登录,请联系管理员!"); + } + + AgentInfo agentInfo = agentInfoService.getById(sysUserEntity.getBelongInfoId()); + if (agentInfo == null) { + throw JeepayAuthenticationException.build("服务商信息不存在!"); + } + + return new JeeUserDetails(baseConverter.toModel(sysUserEntity), auth.getCredential(), agentInfo.getState()); + + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/WebSecurityConfig.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/WebSecurityConfig.java new file mode 100644 index 0000000..2897a81 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/secruity/WebSecurityConfig.java @@ -0,0 +1,136 @@ +package com.jeequan.jeepay.agent.secruity; + +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/* + * Spring Security 配置项 + * + * @author terrfly + * + * @date 2021/6/8 17:11 + */ +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) //开启@PreAuthorize @PostAuthorize 等前置后置安全校验注解 +public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ + + @Autowired private UserDetailsService userDetailsService; + @Autowired private JeeAuthenticationEntryPoint unauthorizedHandler; + @Autowired private SystemYmlConfig systemYmlConfig; + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + + + /** + * 使用BCrypt强哈希函数 实现PasswordEncoder + * **/ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Autowired + public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { + authenticationManagerBuilder + .userDetailsService(this.userDetailsService) + .passwordEncoder(passwordEncoder()); + } + + /** 允许跨域请求 **/ + @Bean + public CorsFilter corsFilter() { + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + if(systemYmlConfig.getAllowCors()){ + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); //带上cookie信息 +// config.addAllowedOrigin(CorsConfiguration.ALL); //允许跨域的域名, *表示允许任何域名使用 + config.addAllowedOriginPattern(CorsConfiguration.ALL); //使用addAllowedOriginPattern 避免出现 When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead. + config.addAllowedHeader(CorsConfiguration.ALL); //允许任何请求头 + config.addAllowedMethod(CorsConfiguration.ALL); //允许任何方法(post、get等) + source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效 + } + return new CorsFilter(source); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // 由于使用的是JWT,我们这里不需要csrf + .csrf().disable() + + .cors().and() + + // 认证失败处理方式 + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + + // 基于token,所以不需要session + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + + .authorizeRequests() + + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated(); + + // 添加JWT filter + httpSecurity.addFilterBefore(new JeeAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class); + + // 禁用缓存 + httpSecurity.headers().cacheControl(); + } + + @Override + public void configure(WebSecurity web) throws Exception { + //ignore文件 : 无需进入spring security 框架 + // 1.允许对于网站静态资源的无授权访问 + // 2.对于获取token的rest api要允许匿名访问 + web.ignoring().antMatchers( + HttpMethod.GET, + "/", + "/*.html", + "/favicon.ico", + "/**/*.html", + "/**/*.css", + "/**/*.js", + "/**/*.png", + "/**/*.jpg", + "/**/*.jpeg", + "/**/*.svg", + "/**/*.ico", + "/**/*.webp", + "/*.txt", + "/**/*.xls", + "/**/*.mp4" //支持mp4格式的文件匿名访问 + ) + .antMatchers( + "/api/anon/**", //匿名访问接口 + "/api/pos/**", //匿名访问接口,pos机设备 + "/api/advert/appAdvert/**" //匿名访问接口,广告接口 + ); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/AuthService.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/AuthService.java new file mode 100644 index 0000000..32f2906 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/AuthService.java @@ -0,0 +1,362 @@ +package com.jeequan.jeepay.agent.service; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.agent.config.SystemYmlConfig; +import com.jeequan.jeepay.bizcommons.manage.auth.AuthManage; +import com.jeequan.jeepay.converter.BaseConverter; +import com.jeequan.jeepay.core.cache.ITokenService; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.JeepayAuthenticationException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.jwt.JWTUtils; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.db.entity.AgentConfig; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.service.mapper.SysEntitlementMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.*; + +/** + * 认证Service + * + * @modify zhuxiao + * + * @date 2021-04-27 15:50 + */ +@Slf4j +@Service +public class AuthService { + + @Resource + private AuthenticationManager authenticationManager; + + @Autowired + private SysUserService sysUserService; + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysRoleEntRelaService sysRoleEntRelaService; + @Autowired + private AgentInfoService agentInfoService; + @Autowired + private SysEntitlementMapper sysEntitlementMapper; + @Autowired + private SystemYmlConfig systemYmlConfig; + @Autowired + private UserDetailsService userDetailsService; + @Autowired + private AuthManage authManage; + + @Autowired + private BaseConverter baseConverter; + + @Autowired private AgentConfigService agentConfigService; + + /** + * 登录认证(密码登录, 包含MFA二次认证校验) + **/ + public ApiRes authByAuthentication(String username, String password, String loginType, String vercodeToken, String mfaCode) { + + // 防穷举判断 + authManage.loginErrValidate(CS.SYS_ROLE_TYPE.AGENT, username); + + //1. 生成spring-security usernamePassword类型对象 + UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); + + //spring-security 自动认证过程; + // 1. 进入 JeeUserDetailsServiceImpl.loadUserByUsername 获取用户基本信息; + //2. SS根据UserDetails接口验证是否用户可用; + //3. 最后返回loadUserByUsername 封装的对象信息; + Authentication authentication = null; + try { + authentication = authenticationManager.authenticate(upToken); + } catch (JeepayAuthenticationException jex) { + throw jex.getBizException() == null ? new BizException(jex.getMessage()) : jex.getBizException(); + } catch (BadCredentialsException e) { + + // 防穷举累加 + authManage.loginErrCount(CS.SYS_ROLE_TYPE.AGENT, username); + + // throw new BizException("用户名/密码错误!"); + } catch (AuthenticationException e) { + log.error("AuthenticationException:", e); + throw new BizException("认证服务出现异常, 请重试或联系系统管理员!"); + } + JeeUserDetails jeeUserDetails = (JeeUserDetails) authentication.getPrincipal(); + SysUser sysUser = jeeUserDetails.getSysUser(); + + // 第一次登录 && 该用户是否已经绑定MFA验证 : 返回前端,需要MFA的二次认证 + if (StringUtils.isEmpty(mfaCode) && sysUser.getMfaBindState() == CS.YES) { + return ApiRes.ok4newJson("isMFA", true); + } + + // mfaCode != null 说明: 二次输入的验证, 需要验证MFA验证码 + if (StringUtils.isNotEmpty(mfaCode)) { + sysUserService.checkMFACode(sysUser.getSysUserId(), mfaCode); + } + + // 删除图形验证码缓存数据 & 返回accessToken + RedisUtil.del(CS.getCacheKeyImgCode(vercodeToken)); + String accessToken = userDetailsProcess(jeeUserDetails, loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.PASSWD); + + // 更新上次登录时间 + sysUserService.updateLastLoginTime(sysUser.getSysUserId()); + + JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken); + tokenRes.put("lastLoginTime", jeeUserDetails.getSysUser().getLastLoginTime()); + + AgentInfo agentInfo = agentInfoService.getById(sysUser.getUserNo()); + List agentNoList = new ArrayList<>(); + Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> { + agentNoList.addAll(Arrays.asList(item.split(","))); + }); + + agentNoList.add(agentInfo.getAgentNo()); + + List list = agentConfigService.lambdaQuery() + .in(AgentConfig::getAgentNo, agentNoList) + .eq(AgentConfig::getGroupKey, "agentSiteConfig") + .eq(AgentConfig::getConfigKey, "agentSiteUrl") + .list(); + + if (!list.isEmpty()) { + tokenRes.put("oemSiteUrl", list.get(0).getConfigVal()); + } + return ApiRes.ok(tokenRes); + } + + /** + * 认证(手机验证码方式) + */ + public ApiRes authByPhoneCode(String phone, String loginType) { + + JeeUserDetails jeeUserDetails = (JeeUserDetails) userDetailsService.loadUserByUsername(phone); + String accessToken = userDetailsProcess(jeeUserDetails, loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.TEL_CODE); + + // 更新上次登录时间 + sysUserService.updateLastLoginTime(jeeUserDetails.getSysUserId()); + + JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken); + tokenRes.put("lastLoginTime", jeeUserDetails.getSysUser().getLastLoginTime()); + + AgentInfo agentInfo = agentInfoService.getById(jeeUserDetails.getSysUser().getUserNo()); + List agentNoList = new ArrayList<>(); + Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> { + agentNoList.addAll(Arrays.asList(item.split(","))); + }); + + agentNoList.add(agentInfo.getAgentNo()); + + List list = agentConfigService.lambdaQuery() + .in(AgentConfig::getAgentNo, agentNoList) + .eq(AgentConfig::getGroupKey, "agentSiteConfig") + .eq(AgentConfig::getConfigKey, "agentSiteUrl") + .list(); + + if (!list.isEmpty()) { + tokenRes.put("oemSiteUrl", list.get(0).getConfigVal()); + } + + return ApiRes.ok(tokenRes); + } + + /** + * 认证(app扫码登录方式) + */ + public JSONObject authByAppQrcode(Long sysUserId, String loginType) { + + SysUserEntity sysUser = sysUserService.getById(sysUserId); + if (sysUser == null || sysUser.getState() != CS.YES) { + throw new BizException("用户不存在或状态不可用"); + } + + String accessToken = userDetailsProcess(userDetailsService.loadUserByUsername(sysUser.getLoginUsername()), loginType, null, JWTPayload.CREDENTIAL_AUTH_TYPE.QR_CODE); + + // 更新上次登录时间 + sysUserService.updateLastLoginTime(sysUserId); + + JSONObject tokenRes = JsonKit.newJson(CS.ACCESS_TOKEN_NAME, accessToken); + tokenRes.put("lastLoginTime", sysUser.getLastLoginTime()); + + AgentInfo agentInfo = agentInfoService.getById(sysUser.getUserNo()); + List agentNoList = new ArrayList<>(); + Optional.ofNullable(agentInfo.getPidArr()).ifPresent(item -> { + agentNoList.addAll(Arrays.asList(item.split(","))); + }); + + agentNoList.add(agentInfo.getAgentNo()); + + List list = agentConfigService.lambdaQuery() + .in(AgentConfig::getAgentNo, agentNoList) + .eq(AgentConfig::getGroupKey, "agentSiteConfig") + .eq(AgentConfig::getConfigKey, "agentSiteUrl") + .list(); + + if (!list.isEmpty()) { + tokenRes.put("oemSiteUrl", list.get(0).getConfigVal()); + } + + return tokenRes; + } + + // 通过 sysUserId 登录 (一般在app延期使用) + public String authBySysUserId(Long sysUserId, String loginType, String existsCacheKey) { + SysUserEntity sysUser = sysUserService.getById(sysUserId); + + if (sysUser == null || sysUser.getState() != CS.YES) { + throw new BizException("用户不存在或状态不可用"); + } + + return userDetailsProcess(userDetailsService.loadUserByUsername(sysUser.getLoginUsername()), loginType, existsCacheKey, null); + } + + + /** + * 根据用户ID 更新缓存中的权限集合, 使得分配实时生效 + **/ + public void refAuthentication(List sysUserIdList) { + + if (sysUserIdList == null || sysUserIdList.isEmpty()) { + return; + } + + Map sysUserMap = new HashMap<>(); + + // 查询 sysUserId 和 state + sysUserService.lambdaQuery() + .in(SysUserEntity::getSysUserId, sysUserIdList) + .list() + .forEach(item -> sysUserMap.put(item.getSysUserId(), item)); + + for (Long sysUserId : sysUserIdList) { + + Collection cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(sysUserId, "*")); + if (cacheKeyList == null || cacheKeyList.isEmpty()) { + continue; + } + + for (String cacheKey : cacheKeyList) { + + //用户不存在 || 已禁用 需要删除Redis + SysUserEntity sysUser = sysUserMap.get(sysUserId); + if (sysUser == null || sysUser.getState() == CS.PUB_DISABLE) { + RedisUtil.del(cacheKey); + continue; + } + + JeeUserDetails jwtBaseUser = RedisUtil.getObject(cacheKey, JeeUserDetails.class); + if (jwtBaseUser != null) { + // 重新放置sysUser对象 + jwtBaseUser.setSysUser(baseConverter.toModel(sysUser)); + + //查询放置权限数据 + jwtBaseUser.setAuthorities(getUserAuthority(jwtBaseUser.getSysUser())); + + //保存token 失效时间不变 + RedisUtil.set(cacheKey, jwtBaseUser); + } + } + } + + } + + /** + * 根据用户ID 删除用户缓存信息 + **/ + public void delAuthentication(List sysUserIdList) { + if (sysUserIdList == null || sysUserIdList.isEmpty()) { + return; + } + for (Long sysUserId : sysUserIdList) { + Collection cacheKeyList = RedisUtil.keys(CS.getCacheKeyToken(sysUserId, "*")); + if (cacheKeyList == null || cacheKeyList.isEmpty()) { + continue; + } + for (String cacheKey : cacheKeyList) { + RedisUtil.del(cacheKey); + } + } + } + + public List getUserAuthority(SysUser sysUser) { + + //用户拥有的角色集合 需要以ROLE_ 开头, 用户拥有的权限集合 + List roleList = sysRoleService.findListByUser(sysUser.getSysUserId()); + List entList = sysRoleEntRelaService.selectEntIdsByUserId(sysUser.getSysUserId(), sysUser.getUserType(), sysUser.getSysType()); + + List grantedAuthorities = new LinkedList<>(); + roleList.forEach(role -> grantedAuthorities.add(new SimpleGrantedAuthority(role))); + entList.forEach(ent -> grantedAuthorities.add(new SimpleGrantedAuthority(ent))); + return grantedAuthorities; + } + + /** + * 获取到userDetail之后的操作 + **/ + public String userDetailsProcess(UserDetails userDetails, String loginType, String existsCacheKey, String authType) { + + JeeUserDetails jeeUserDetails = (JeeUserDetails) userDetails; + + // 登录认证类型 + if (StringUtils.isNotEmpty(authType)) { + jeeUserDetails.setAuthType(authType); + } + + // 登录方式 + jeeUserDetails.setLoginType(loginType); + + //验证通过后 再查询用户角色和权限信息集合 + + SysUser sysUser = jeeUserDetails.getSysUser(); + + // 普通操作员 && 不包含左侧菜单 进行错误提示 (超管 or 扩展员都是通过菜单定义进行查询全部菜单进行过滤,只有普通操作员通过角色功能进行划分) + if (sysUser.getUserType() == SysUser.UEST_TYPE_NORMAL + && sysEntitlementMapper.userHasLeftMenu(sysUser.getSysUserId(), CS.SYS_ROLE_TYPE.AGENT) <= 0) { + throw new BizException("当前用户未分配任何菜单权限,请联系管理员进行分配后再登录!"); + } + + // 查询当前用户的服务商信息 + AgentInfo agentInfo = agentInfoService.getById(sysUser.getBelongInfoId()); + if (agentInfo != null && (agentInfo.getState() == CS.NO)) { + throw new BizException("当前服务商状态不可用!"); + } + // 放置权限集合 + jeeUserDetails.setAuthorities(getUserAuthority(sysUser)); + + //生成token + String cacheKey = StringUtils.isNotEmpty(existsCacheKey) ? existsCacheKey : CS.getCacheKeyToken(sysUser.getSysUserId(), IdUtil.fastUUID()); + + //生成iToken 并放置到缓存 + ITokenService.processTokenCache(jeeUserDetails, cacheKey); //处理token 缓存信息 + + //将信息放置到Spring-security context中 + UsernamePasswordAuthenticationToken authenticationRest = new UsernamePasswordAuthenticationToken(jeeUserDetails, null, jeeUserDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authenticationRest); + + //返回JWTToken + return JWTUtils.generateToken(new JWTPayload(jeeUserDetails), systemYmlConfig.getJwtSecret()); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/CodeSysTypeManager.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/CodeSysTypeManager.java new file mode 100644 index 0000000..d619b39 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/service/CodeSysTypeManager.java @@ -0,0 +1,14 @@ +package com.jeequan.jeepay.agent.service; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.ICodeSysTypeManager; +import org.springframework.stereotype.Component; + +@Component +public class CodeSysTypeManager implements ICodeSysTypeManager { + + @Override + public String getCodeSysName() { + return CS.CODE_SYS_NAME_SET.JEEPAY_AGENT; + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/util/CodeImgUtil.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/util/CodeImgUtil.java new file mode 100644 index 0000000..1d8f1f0 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/util/CodeImgUtil.java @@ -0,0 +1,341 @@ +package com.jeequan.jeepay.agent.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.zxing.*; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URL; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* +* 二维码生成器 +* +* @author terrfly +* +* @date 2021/6/8 17:54 +*/ +public class CodeImgUtil { + + private static final Logger _log = LoggerFactory.getLogger(CodeImgUtil.class); + + // 二维码尺寸List + private static List sizeList = new ArrayList(); + + static { + sizeList.add(258); + sizeList.add(344); + sizeList.add(430); + sizeList.add(860); + sizeList.add(1280); + } + + public static List getEwmSizeList() { + return sizeList; + } + + + // 图片宽度的一般 + private static final int IMAGE_WIDTH = 25; + private static final int IMAGE_HEIGHT = 25; + private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; + private static final int FRAME_WIDTH = 2; + + // 二维码写码器 + private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); + + /** + * + * @param content + * 二维码显示的文本 + * @param width + * 二维码的宽度 + * @param height + * 二维码的高度 + * @param srcImagePath + * 中间嵌套的图片 + * @param destImagePath + * 二维码生成的地址 + */ + public static void encode(String content, int width, int height, + String srcImagePath, String destImagePath, String fileName) { + try { + File dir = new File(destImagePath); + _log.error("==================" + destImagePath); + _log.error("==================" + srcImagePath); + if (!dir.exists()) { + _log.error("==================notExist"); + boolean result = dir.mkdirs(); + _log.error("==================midirsResult" + result); + } + // ImageIO.write 参数 1、BufferedImage 2、输出的格式 3、输出的文件 + ImageIO.write(genBarcode(content, width, height, srcImagePath), + "jpg", new File(destImagePath + fileName)); + + } catch (Exception e) { + _log.error("生成二维码出错", e); + } + } + + /** + * 得到BufferedImage + * + * @param content + * 二维码显示的文本 + * @param width + * 二维码的宽度 + * @param height + * 二维码的高度 + * @param srcImagePath + * 中间嵌套的图片 + * @return + * @throws WriterException + * @throws IOException + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static BufferedImage genBarcode(String content, int width, + int height, String srcImagePath) throws WriterException, + IOException { + // 读取源图像 + BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, + IMAGE_HEIGHT, false); + + int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; + for (int i = 0; i < scaleImage.getWidth(); i++) { + for (int j = 0; j < scaleImage.getHeight(); j++) { + srcPixels[i][j] = scaleImage.getRGB(i, j); + } + } + + java.util.Hashtable hint = new java.util.Hashtable(); + hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); + hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hint.put(EncodeHintType.MARGIN, 1); + // 生成二维码 + BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, + width, height, hint); + + // 二维矩阵转为一维像素数组 + int halfW = matrix.getWidth() / 2; + int halfH = matrix.getHeight() / 2; + int[] pixels = new int[width * height]; + + for (int y = 0; y < matrix.getHeight(); y++) { + for (int x = 0; x < matrix.getWidth(); x++) { + // 读取图片 + if (x > halfW - IMAGE_HALF_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + && y > halfH - IMAGE_HALF_WIDTH + && y < halfH + IMAGE_HALF_WIDTH) { + pixels[y * width + x] = srcPixels[x - halfW + + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; + } + // 在图片四周形成边框 + else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + - IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { + pixels[y * width + x] = 0xfffffff; + } else { + // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; + pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 + : 0xfffffff; + } + } + } + + BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + image.getRaster().setDataElements(0, 0, width, height, pixels); + + return image; + } + + /** + * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 + * + * @param srcImageFile + * 源文件地址 + * @param height + * 目标高度 + * @param width + * 目标宽度 + * @param hasFiller + * 比例不对时是否需要补白:true为补白; false为不补白; + * @throws IOException + */ + private static BufferedImage scale(String srcImageFile, int height, + int width, boolean hasFiller) throws IOException { + double ratio = 0.0; // 缩放比例 + + URL url = new URL(srcImageFile); + + BufferedImage srcImage = ImageIO.read(url); + Image destImage = srcImage.getScaledInstance(width, height, + BufferedImage.SCALE_SMOOTH); + // 计算比例 + if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { + if (srcImage.getHeight() > srcImage.getWidth()) { + ratio = (new Integer(height)).doubleValue() + / srcImage.getHeight(); + } else { + ratio = (new Integer(width)).doubleValue() + / srcImage.getWidth(); + } + AffineTransformOp op = new AffineTransformOp(AffineTransform + .getScaleInstance(ratio, ratio), null); + destImage = op.filter(srcImage, null); + } + if (hasFiller) {// 补白 + BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + Graphics2D graphic = image.createGraphics(); + graphic.setColor(Color.white); + graphic.fillRect(0, 0, width, height); + if (width == destImage.getWidth(null)) { + graphic.drawImage(destImage, 0, (height - destImage + .getHeight(null)) / 2, destImage.getWidth(null), + destImage.getHeight(null), Color.white, null); + } else { + graphic.drawImage(destImage, + (width - destImage.getWidth(null)) / 2, 0, destImage + .getWidth(null), destImage.getHeight(null), + Color.white, null); + } + graphic.dispose(); + destImage = image; + } + return (BufferedImage) destImage; + } + + /** + * 生成图像 + * filePath 存放图片的路径 + * fileName 图片的名称 + * info 生成图片的链接地址(例如:weixin://wxpay/s/Anp43md) + * width 图片的宽度 + * height 图片的高度 + * @throws WriterException + * @throws IOException + */ + public static String codeImgEncode(String filePath, String fileName, String info, int width, int height) throws WriterException, IOException { + String format="png"; + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + BitMatrix bitMatrix = new MultiFormatWriter().encode(info, + BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 + Path path = FileSystems.getDefault().getPath(filePath, fileName); + File dir = new File(filePath); + _log.error("==================" + filePath); + if (!dir.exists()) { + _log.error("==================notExist"); + boolean result = dir.mkdirs(); + _log.error("==================midirsResult" + result); + } + MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 输出图像 + return path.toString(); + } + + + public static void writeQrCode(OutputStream stream, String info, int width, int height) throws WriterException, IOException { + String format="png"; + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.MARGIN,0); + BitMatrix bitMatrix = new MultiFormatWriter().encode(info, + BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 + bitMatrix = deleteWhite(bitMatrix); + BufferedImage bi = MatrixToImageWriter.toBufferedImage(bitMatrix); + bi = zoomInImage(bi,width,height); + ImageIO.write(bi,format,stream); // 输出图像 + //MatrixToImageWriter.writeToStream(bitMatrix, format, stream);// 输出图像 + } + + + /** + * 解析图像 + */ + public static void codeImgDecode() { + String filePath = "D://zxing.png"; + BufferedImage image; + try { + image = ImageIO.read(new File(filePath)); + LuminanceSource source = new BufferedImageLuminanceSource(image); + Binarizer binarizer = new HybridBinarizer(source); + BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); + Map hints = new HashMap(); + hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); + Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码 + JSONObject content = JSON.parseObject(result.getText()); + System.out.println("图片中内容: "); + System.out.println("author: " + content.getString("author")); + System.out.println("zxing: " + content.getString("zxing")); + System.out.println("图片中格式: "); + System.out.println("encode: " + result.getBarcodeFormat()); + } catch (IOException e) { + e.printStackTrace(); + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + + /** + * 去除白边 + * */ + private static BitMatrix deleteWhite(BitMatrix matrix) { + int[] rec = matrix.getEnclosingRectangle(); + int resWidth = rec[2] + 1; + int resHeight = rec[3] + 1; + + BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); + resMatrix.clear(); + for (int i = 0; i < resWidth; i++) { + for (int j = 0; j < resHeight; j++) { + if (matrix.get(i + rec[0], j + rec[1])) { + resMatrix.set(i, j); + } + } + } + return resMatrix; + } + + public static BufferedImage zoomInImage(BufferedImage originalImage, int wigth, int height){ + BufferedImage newImage = new BufferedImage(wigth,height,originalImage.getType()); + Graphics g = newImage.getGraphics(); + g.drawImage(originalImage,0,0,wigth,height,null); + g.dispose(); + return newImage; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResBodyAdvice.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResBodyAdvice.java new file mode 100644 index 0000000..81ef48f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResBodyAdvice.java @@ -0,0 +1,55 @@ +package com.jeequan.jeepay.agent.web; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.utils.ApiResBodyAdviceKit; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +/** + * 自定义springMVC返回数据格式 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +@ControllerAdvice +public class ApiResBodyAdvice implements ResponseBodyAdvice { + + /** 判断哪些需要拦截 **/ + @Override + public boolean supports(MethodParameter returnType, Class converterType) { + return true; + } + + /** 拦截返回数据处理 */ + @Override + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, + Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { + + // 如果为 ApiRes && code为成功态 根据设置做数据传输的加密项 && 系统配置的为传输加密 + if( body instanceof ApiRes && ((ApiRes)body).getCode() != null && ((ApiRes)body).getCode().equals(ApiCodeEnum.SUCCESS.getCode()) + && SysConfigService.HTTP_MSG_IS_ENCRYPT + ){ + + // 获取到转换后的格式,并且转回ApiRes + ApiRes result = ((JSONObject)ApiResBodyAdviceKit.beforeBodyWrite(body)).toJavaObject(ApiRes.class); + if(result.getData() != null){ //若原始数据不为空 + result.setEncryptData(SysConfigService.HTTP_MESSAGE_ENCRYPT_SM4.encryptBase64(JsonKit.newJson("originData", result.getData()).toJSONString())); + result.setData(null); + } + return result; + } + + //处理扩展字段 + return ApiResBodyAdviceKit.beforeBodyWrite(body); + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResInterceptor.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResInterceptor.java new file mode 100644 index 0000000..a6f23f4 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApiResInterceptor.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.agent.web; + +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 数据响应拦截器 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +@Component +public class ApiResInterceptor implements HandlerInterceptor { + + /** postHandler是在请求结束之后, 视图渲染之前执行的,但只有preHandle方法返回true的时候才会执行 + * 如果ctrl使用了@RestController或者@ResponseBody注解 则ModelAndView = null, 因为不走视图转换器, 而是走的RequestResponseBodyMethodProcessor。 + * ———————————————— + * + * **/ + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + + //do + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApplicationContextKit.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApplicationContextKit.java new file mode 100644 index 0000000..6bcdfc4 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/ApplicationContextKit.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.agent.web; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Service; +import org.springframework.web.context.ServletContextAware; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +/** + * 上下文配置 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +@Service +public class ApplicationContextKit implements ServletContextAware,InitializingBean{ + + private ServletContext servletContext ; + @Override + public void setServletContext(ServletContext servletContext) { + + this.servletContext = servletContext; + } + + /** + * afterPropertiesSet 是在什么之后执行? 启动顺序是? + * 调用PropKit(SpringBeansUtil.getBean获取方式) 会不会出现找不到bean的问题? + * + * */ + @Override + public void afterPropertiesSet() throws Exception { + + } + + /** + * 仅在项目启动完成,并且在req请求中使用!! + * @param key + * @return + */ + public static Object getReqSession(String key){ + + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + + return request.getSession().getAttribute(key); + + } + + /** + * 仅在项目启动完成,并且在req请求中使用!! + * @param key + * @return + */ + public static void clearSession(String key){ + + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + + request.getSession().removeAttribute(key); + + } + + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/WebmvcConfig.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/WebmvcConfig.java new file mode 100644 index 0000000..e796620 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/web/WebmvcConfig.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.agent.web; + +import com.jeequan.jeepay.core.config.WebConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; + +/** + * webmvc配置 + * + * @author terrfly + * @modify zhuxiao + * @date 2021-04-27 15:50 + */ +@Configuration +public class WebmvcConfig extends WebConfig { + + @Autowired + private ApiResInterceptor apiResInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + super.addInterceptors(registry); + registry.addInterceptor(apiResInterceptor); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/config/WebSocketConfig.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/config/WebSocketConfig.java new file mode 100644 index 0000000..7b736ae --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/config/WebSocketConfig.java @@ -0,0 +1,21 @@ +package com.jeequan.jeepay.agent.websocket.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/* +* 开启WebSocket支持 +* +* @author terrfly +* +* @date 2021/6/22 12:57 +*/ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsChannelUserIdServer.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsChannelUserIdServer.java new file mode 100644 index 0000000..4f7c94f --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsChannelUserIdServer.java @@ -0,0 +1,152 @@ +package com.jeequan.jeepay.agent.websocket.server; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * WebSocket服务类 + * /ws/channelUserId/{appId}/{客戶端自定義ID} + * + * @author terrfly + * + * @date 2021/8/13 18:57 + */ +@ServerEndpoint("/api/anon/ws/channelUserId/{appId}/{cid}") +@Component +public class WsChannelUserIdServer { + + private final static Logger logger = LoggerFactory.getLogger(WsChannelUserIdServer.class); + + //当前在线客户端 数量 + private static int onlineClientSize = 0; + + // appId 与 WsPayOrderServer 存储关系, ConcurrentHashMap保证线程安全 + private static Map> wsAppIdMap = new ConcurrentHashMap<>(); + + //与某个客户端的连接会话,需要通过它来给客户端发送数据 + private Session session; + + //客户端自定义ID + private String cid = ""; + + //支付订单号 + private String appId = ""; + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("appId") String appId, @PathParam("cid") String cid) { + + try { + //设置当前属性 + this.cid = cid; + this.appId = appId; + this.session = session; + + Set wsServerSet = wsAppIdMap.get(appId); + if(wsServerSet == null) { + wsServerSet = new CopyOnWriteArraySet<>(); + } + wsServerSet.add(this); + wsAppIdMap.put(appId, wsServerSet); + + addOnlineCount(); //在线数加1 + logger.info("cid[{}],appId[{}]连接开启监听!当前在线人数为{}", cid, appId, onlineClientSize); + + } catch (Exception e) { + logger.error("ws监听异常cid[{}],appId[{}]", cid, appId, e); + } + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + + Set wsSet = wsAppIdMap.get(this.appId); + wsSet.remove(this); + if(wsSet.isEmpty()) { + wsAppIdMap.remove(this.appId); + } + + subOnlineCount(); //在线数减1 + logger.info("cid[{}],appId[{}]连接关闭!当前在线人数为{}", cid, appId, onlineClientSize); + } + + /** + * @param session + * @param error + */ + @OnError + public void onError(Session session, Throwable error) { + logger.error("ws发生错误", error); + } + + /** + * 实现服务器主动推送 + */ + public void sendMessage(String message) throws IOException { + this.session.getBasicRemote().sendText(message); + } + + /** + * 根据订单ID,推送消息 + * 捕捉所有的异常,避免影响业务。 + * @param appId + */ + public static void sendMsgByAppAndCid(String appId, String cid, String msg) { + + try { + logger.info("推送ws消息到浏览器, appId={}, cid={}, msg={}", appId, cid, msg); + + + Set wsSet = wsAppIdMap.get(appId); + if(wsSet == null || wsSet.isEmpty()){ + logger.info("appId[{}] 无ws监听客户端", appId); + return ; + } + + for (WsChannelUserIdServer item : wsSet) { + if(!cid.equals(item.cid)){ + continue; + } + try { + item.sendMessage(msg); + } catch (Exception e) { + logger.info("推送设备消息时异常,appId={}, cid={}", appId, item.cid, e); + continue; + } + } + } catch (Exception e) { + logger.info("推送消息时异常,appId={}", appId, e); + } + } + + public static synchronized int getOnlineClientSize() { + return onlineClientSize; + } + + public static synchronized void addOnlineCount() { + onlineClientSize++; + } + + public static synchronized void subOnlineCount() { + onlineClientSize--; + } + +} diff --git a/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsPayOrderServer.java b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsPayOrderServer.java new file mode 100644 index 0000000..9b14971 --- /dev/null +++ b/jeepay-agent/src/main/java/com/jeequan/jeepay/agent/websocket/server/WsPayOrderServer.java @@ -0,0 +1,149 @@ +package com.jeequan.jeepay.agent.websocket.server; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +/* + * WebSocket服务类 + * /ws/payOrder/{訂單ID}/{客戶端自定義ID} + * + * @author terrfly + * + * @date 2021/6/22 12:57 + */ +@ServerEndpoint("/api/anon/ws/payOrder/{payOrderId}/{cid}") +@Component +public class WsPayOrderServer { + + private final static Logger logger = LoggerFactory.getLogger(WsPayOrderServer.class); + + //当前在线客户端 数量 + private static int onlineClientSize = 0; + + // payOrderId 与 WsPayOrderServer 存储关系, ConcurrentHashMap保证线程安全 + private static Map> wsOrderIdMap = new ConcurrentHashMap<>(); + + //与某个客户端的连接会话,需要通过它来给客户端发送数据 + private Session session; + + //客户端自定义ID + private String cid = ""; + + //支付订单号 + private String payOrderId = ""; + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("payOrderId") String payOrderId, @PathParam("cid") String cid) { + + try { + //设置当前属性 + this.cid = cid; + this.payOrderId = payOrderId; + this.session = session; + + Set wsServerSet = wsOrderIdMap.get(payOrderId); + if(wsServerSet == null) { + wsServerSet = new CopyOnWriteArraySet<>(); + } + wsServerSet.add(this); + wsOrderIdMap.put(payOrderId, wsServerSet); + + addOnlineCount(); //在线数加1 + logger.info("cid[{}],payOrderId[{}]连接开启监听!当前在线人数为{}", cid, payOrderId, onlineClientSize); + + } catch (Exception e) { + logger.error("ws监听异常cid[{}],payOrderId[{}]", cid, payOrderId, e); + } + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + + Set wsSet = wsOrderIdMap.get(this.payOrderId); + wsSet.remove(this); + if(wsSet.isEmpty()) { + wsOrderIdMap.remove(this.payOrderId); + } + + subOnlineCount(); //在线数减1 + logger.info("cid[{}],payOrderId[{}]连接关闭!当前在线人数为{}", cid, payOrderId, onlineClientSize); + } + + /** + * @param session + * @param error + */ + @OnError + public void onError(Session session, Throwable error) { + logger.error("ws发生错误", error); + } + + /** + * 实现服务器主动推送 + */ + public void sendMessage(String message) throws IOException { + this.session.getBasicRemote().sendText(message); + } + + /** + * 根据订单ID,推送消息 + * 捕捉所有的异常,避免影响业务。 + * @param payOrderId + */ + public static void sendMsgByOrderId(String payOrderId, String msg) { + + try { + logger.info("推送ws消息到浏览器, payOrderId={},msg={}", payOrderId, msg); + + + Set wsSet = wsOrderIdMap.get(payOrderId); + if(wsSet == null || wsSet.isEmpty()){ + logger.info("payOrderId[{}] 无ws监听客户端", payOrderId); + return ; + } + + for (WsPayOrderServer item : wsSet) { + try { + item.sendMessage(msg); + } catch (Exception e) { + logger.info("推送设备消息时异常,payOrderId={}, cid={}", payOrderId, item.cid, e); + continue; + } + } + } catch (Exception e) { + logger.info("推送消息时异常,payOrderId={}", payOrderId, e); + } + } + + public static synchronized int getOnlineClientSize() { + return onlineClientSize; + } + + public static synchronized void addOnlineCount() { + onlineClientSize++; + } + + public static synchronized void subOnlineCount() { + onlineClientSize--; + } + +} diff --git a/jeepay-agent/src/main/resources/application-dev.yml b/jeepay-agent/src/main/resources/application-dev.yml new file mode 100644 index 0000000..abce30c --- /dev/null +++ b/jeepay-agent/src/main/resources/application-dev.yml @@ -0,0 +1,121 @@ +################################# +# spring boot支持外部application.yml 读取优先级为: +# 1、file:./config/(当前目录下的config文件夹) +# 2、file:./(当前目录) +# 3、classpath:/config/(classpath下的config目录) +# 4、classpath:/(classpath根目录) +# 建议: 如果是jar则放置到与jar相同的目录下, 如果解压文件放置到classpath: config目录下。 (需要将文件重命名为 application.yml ) +# +# 该yml文件只配置与环境相关的参数, 其他配置读取项目下的配置项 +# +################################# + +# 数据库的配置项, 自定义配置放置在配置顶层 +#db-config: +# master: #主库配置(必填) +# # yml填写url连接串, 无需将&符号进行转义 +# url: jdbc:mysql://127.0.0.1:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true +# username: root +# password: YinShangFuMysql@123456 +# encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 +# # 连接池配置项 +# initial-size: 5 #初始化时建立物理连接的个数 +# min-idle: 5 #最小连接池数量 +# max-active: 30 #最大连接池数量 +# max-wait: 60000 #获取连接时最大等待时间,单位毫秒 +# # 检测相关 +# test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 +# test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 +# test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 +# time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 +# min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 +# validation-query: SELECT 1 FROM DUAL +# # 是否缓存preparedStatement +# pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 +# max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 +# # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 +# filters: stat,wall +# connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +# +# slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + + # #activeMQ配置 ( 注意: activeMQ配置项需在spring的下级 ) +# activemq: +# broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) #连接地址 +# in-memory: false # Jeepay项目不可使用内存模式, 需要连接多个消费者。 +# user: system # activeMQ默认无需账密认证。 打开认证:activemq.xml添加simpleAuthenticationPlugin标签,账密在credentials.properties文件。 +# password: manager +# pool: +# enabled: true +# max-connections: 10 +# idle-timeout: 30000 # 空闲的连接过期时间,默认为30秒 + # + #rabbitmq配置 ( 注意: rabbitmq配置项需在spring的下级 ) + + + ## rocketmq配置 ( 注意:rocketmq配置项请放置到根目录, 不是spring的二级配置! ) + #rocketmq: + # name-server: 127.0.0.1:9876 + # producer: + # group: JEEPAY-GROUP + + ## 阿里云rocketmq配置 ( 注意:aliyun-rocketmq配置项请放置到根目录, 不是spring的二级配置!需要阿里云开通rocketMQ产品,创建Group和Topic ) + #aliyun-rocketmq: + # namesrvAddr: xxx + # accessKey: xxx + # secretKey: xxx + # groupIdPrefix: GID_JEEPAY_ # (分组前缀, 具体名称详见AliyunRocketMQFactory.java ) + + #日志配置参数。 + # 当存在logback-spring.xml文件时: 该配置将引进到logback配置, springboot配置不生效。 + # 不存在logback-spring.xml 文件时, 使用springboot的配置, 同样可用。 + web: + resources: + static-locations: classpath:/static +logging: + level: + root: debug #主日志级别 + com.jeequan.jeepay: debug #该项目日志级别,当需要打印sql时请开启为debug + file: + path: ./agent/logs #日志存放地址 +#系统业务参数 +isys: + + jwt-secret: N7qDoevBDZYIfHTq #生成jwt的秘钥。 要求每个系统有单独的秘钥管理机制。 + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + # 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! + sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g== + sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB + + + #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] + allow-cors: true + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + + oss: + file-root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) + file-private-path: ${isys.oss.file-root-path}/private #私有化本地访问,不允许url方式公共读取 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) + + mq: + vender: rabbitMQ # 切换MQ厂商, 支持:【 activeMQ rabbitMQ rocketMQ aliYunRocketMQ 】, 需正确配置 【对应的yml参数】 和 【jeepay-components-mq项目下pom.xml中的依赖包】。 + diff --git a/jeepay-agent/src/main/resources/application-prod.yml b/jeepay-agent/src/main/resources/application-prod.yml new file mode 100644 index 0000000..857029d --- /dev/null +++ b/jeepay-agent/src/main/resources/application-prod.yml @@ -0,0 +1,115 @@ +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + cache: + type: redis + redis: + host: 127.0.0.1 + port: 6379 + timeout: 1000 + password: ax123456ax + activemq: + broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) # + in-memory: false # Jeepay + user: admin # activeMQ + password: 123456 + pool: + enabled: true + max-connections: 10 + idle-timeout: 30000 # + web: + resources: + static-locations: classpath:/static +logging: + level: + root: info #主日志级别 +# xxl-job 执行器配置项 +xxl-job: + executor: + admin-address: http://127.0.0.1:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN + # appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + # port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能; + +db-config: + master: #主库配置(必填) + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: yinshangfu + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: yinshangfu + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +isys: + #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] + allow-cors: true + + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + # 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! + sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g== + sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + mq: + vender: activeMQ + + oss: + file-root-path: /home/www/.upload #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) diff --git a/jeepay-agent/src/main/resources/application-test.yml b/jeepay-agent/src/main/resources/application-test.yml new file mode 100644 index 0000000..f5b0c3b --- /dev/null +++ b/jeepay-agent/src/main/resources/application-test.yml @@ -0,0 +1,111 @@ +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + resources: + static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问) + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + cache: + type: redis + redis: + host: 47.111.143.211 + port: 6379 + timeout: 1000 + password: ax123456ax + rabbitmq: + addresses: 47.111.143.211:5672 + username: root + password: YinShangFuRabbit@123456 + dynamic: true + virtual-host: / +logging: + level: + root: info #主日志级别 +# xxl-job 执行器配置项 +xxl-job: + executor: + admin-address: http://47.111.143.211:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN + # appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + # port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能; + +db-config: + master: #主库配置(必填) + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +isys: + #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] + allow-cors: true + + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + # 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! + sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g== + sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + mq: + vender: rabbitMQ + + oss: + file-root-path: D:/jeepayFiles #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) diff --git a/jeepay-agent/src/main/resources/application.yml b/jeepay-agent/src/main/resources/application.yml new file mode 100644 index 0000000..5b7a880 --- /dev/null +++ b/jeepay-agent/src/main/resources/application.yml @@ -0,0 +1,8 @@ +server: + port: 9219 #设置端口 + servlet: + context-path: / #设置应用的目录. 前缀需要带/, 无需设置后缀, 示例 【 /xxx 】 or 【 / 】 +spring: + profiles: + active: dev + diff --git a/jeepay-agent/src/main/resources/banner.txt b/jeepay-agent/src/main/resources/banner.txt new file mode 100644 index 0000000..fb9d690 --- /dev/null +++ b/jeepay-agent/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + __ + / /___ ___ ____ ____ ___ __ + __ / // _ \/ _ \/ __ \/ __ `/ / / / +/ /_/ // __/ __/ /_/ / /_/ / /_/ / +\____/ \___/\___/ .___/\__,_/\__, / + /_/ /____/ + :: Jeepay Plus S3 :: (v3.3.6.RELEASE) + 计全支付 - 让支付接入更简单 : https://www.jeequan.com diff --git a/jeepay-agent/src/main/resources/logback-spring.xml b/jeepay-agent/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..a15b311 --- /dev/null +++ b/jeepay-agent/src/main/resources/logback-spring.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + ${currentLoggerPattern} + + + + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.all.log + + ${currentLoggerPattern} + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.all.%d{yyyy-MM-dd}.log + 5 + + + + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.error.log + + ${currentLoggerPattern} + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.error.%d{yyyy-MM-dd}.log + 20 + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_alipay.png b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_alipay.png new file mode 100644 index 0000000..0e614cf Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_alipay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_unionpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_unionpay.png new file mode 100644 index 0000000..11a422c Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_unionpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_wxpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_wxpay.png new file mode 100644 index 0000000..c7d5b20 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_wxpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_ysfpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_ysfpay.png new file mode 100644 index 0000000..9c94317 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/commons/t_ysfpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/b_default_logo.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/b_default_logo.png new file mode 100644 index 0000000..5813082 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/b_default_logo.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_bg.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_bg.png new file mode 100644 index 0000000..2b36217 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_bg.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_default_logo.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_default_logo.png new file mode 100644 index 0000000..dd90797 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/i_default_logo.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_alipay.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_alipay.png new file mode 100644 index 0000000..0e614cf Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_alipay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_unionpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_unionpay.png new file mode 100644 index 0000000..11a422c Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_unionpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_wxpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_wxpay.png new file mode 100644 index 0000000..c7d5b20 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_wxpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_ysfpay.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_ysfpay.png new file mode 100644 index 0000000..9c94317 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellA/t_ysfpay.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div1.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div1.png new file mode 100644 index 0000000..8ec5078 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div1.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div2.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div2.png new file mode 100644 index 0000000..0ae3c41 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div2.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div3.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div3.png new file mode 100644 index 0000000..c4ccd68 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/div3.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellB/i_default_logo.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/i_default_logo.png new file mode 100644 index 0000000..7803aa7 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellB/i_default_logo.png differ diff --git a/jeepay-agent/src/main/resources/static/images/qrshell/shellC/bg2.png b/jeepay-agent/src/main/resources/static/images/qrshell/shellC/bg2.png new file mode 100644 index 0000000..9236569 Binary files /dev/null and b/jeepay-agent/src/main/resources/static/images/qrshell/shellC/bg2.png differ diff --git a/jeepay-agent/src/main/resources/static/index.html b/jeepay-agent/src/main/resources/static/index.html new file mode 100644 index 0000000..7879e1c --- /dev/null +++ b/jeepay-agent/src/main/resources/static/index.html @@ -0,0 +1,4 @@ + + + + diff --git a/jeepay-agent/src/main/resources/templates/.gitkeep b/jeepay-agent/src/main/resources/templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-agent/src/test/java/.gitkeep b/jeepay-agent/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-agent/src/test/resources/.gitkeep b/jeepay-agent/src/test/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-bill/pom.xml b/jeepay-bill/pom.xml new file mode 100644 index 0000000..ef57659 --- /dev/null +++ b/jeepay-bill/pom.xml @@ -0,0 +1,130 @@ + + + 4.0.0 + + com.jeequan + jeepay-9220-bill + jar + ${isys.version} + Jeepay计全支付系统 [对账系统] + https://www.jeequan.com + + + com.jeequan + jeepay + Final + + + + + ${basedir}/../ + + + + + + + + com.jeequan + jeepay-components-db + + + + + com.jeequan + jeepay-components-3rd + + + + + com.jeequan + jeepay-components-oss + + + + + com.jeequan + jeepay-components-mq + + + + + com.jeequan + jeepay-components-bizcommons + + + + + org.springframework.boot + spring-boot-starter-web + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.module + jackson-module-parameter-names + + + + + + + org.springframework.boot + spring-boot-starter-security + + + + + com.xuxueli + xxl-job-core + + + + + + + + ${project.artifactId} + + + + + src/main/resources**/*.* + + + + ../conf/devCommons + **/*.yml + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + ${session.executionRootDirectory}/target/ + + + + + maven-resources-plugin + + + + + + \ No newline at end of file diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/InitRunner.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/InitRunner.java new file mode 100644 index 0000000..ef4822d --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/InitRunner.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.bill.bootstrap; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.crypto.SmUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializeConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer; +import com.jeequan.jeepay.bill.config.SystemYmlConfig; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/* + * 项目初始化操作 + * 比如初始化配置文件, 读取基础数据, 资源初始化等。 避免在Main函数中写业务代码。 + * CommandLineRunner / ApplicationRunner都可以达到要求, 只是调用参数有所不同。 + * +* +* @author terrfly +* @date 2021/6/8 17:17 +*/ +@Component +public class InitRunner implements CommandLineRunner { + + @Autowired private SystemYmlConfig systemYmlConfig; + + + @Override + public void run(String... args) throws Exception { + + // 配置是否使用缓存模式 + SysConfigService.IS_USE_CACHE = systemYmlConfig.getCacheConfig(); + + // 初始化系统秘钥 + SysConfigService.DB_ENCRYPT_SECRET = systemYmlConfig.getDbEncryptSecret(); + SysConfigService.DB_ENCRYPT_SM4 = SmUtil.sm4(SysConfigService.DB_ENCRYPT_SECRET.getBytes()); + + //初始化处理fastjson格式 + SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance(); + serializeConfig.put(Date.class, new SimpleDateFormatSerializer(DatePattern.NORM_DATETIME_PATTERN)); + + //解决json 序列化时候的 $ref:问题 + JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask(); + + } +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/JeepayBillApplication.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/JeepayBillApplication.java new file mode 100644 index 0000000..a8b2c8d --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/bootstrap/JeepayBillApplication.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.bill.bootstrap; + +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.jeequan.jeepay.bill.config.SystemYmlConfig; +import com.jeequan.jeepay.core.task.XxlJobExecutorProp; +import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @Author terrfly + * @Date 2019/11/7 15:19 + * @Description spring-boot 主启动程序 + **/ +@SpringBootApplication +@EnableScheduling +@MapperScan("com.jeequan.jeepay.service.mapper") //Mybatis mapper接口路径 +@ComponentScan(basePackages = "com.jeequan.jeepay.*") //由于MainApplication没有在项目根目录, 需要配置basePackages属性使得成功扫描所有Spring组件; +@Configuration +public class JeepayBillApplication { + + @Autowired private SystemYmlConfig systemYmlConfig; + + /** main启动函数 **/ + public static void main(String[] args) { + + //启动项目 + SpringApplication.run(JeepayBillApplication.class, args); + + } + + + /** fastJson 配置信息 **/ + @Bean + public HttpMessageConverters fastJsonConfig(){ + + // 开启 FastJSON 安全模式! + ParserConfig.getGlobalInstance().setSafeMode(true); + + //新建fast-json转换器 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); + + //fast-json 配置信息 + FastJsonConfig config = new FastJsonConfig(); + config.setDateFormat("yyyy-MM-dd HH:mm:ss"); + converter.setFastJsonConfig(config); + + //设置响应的 Content-Type + converter.setSupportedMediaTypes(Arrays.asList(new MediaType[]{MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8})); + return new HttpMessageConverters(converter); + } + + /** Mybatis plus 分页插件 **/ + @Bean + public MybatisPlusInterceptor paginationInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false + // paginationInterceptor.setOverflow(false); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + return interceptor; + } + + /*** 注入 定时任务 执行器 **/ + + /** xxl-job执行器配置信息 **/ + @ConfigurationProperties(prefix = "xxl-job.executor") + @Bean + public XxlJobExecutorProp xxlJobExecutorProp() { return new XxlJobExecutorProp(); } + + @Autowired + private XxlJobExecutorProp xxlJobExecutorProp; + + @Bean + public XxlJobSpringExecutor xxlJobExecutor() { + XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); + xxlJobSpringExecutor.setAdminAddresses(xxlJobExecutorProp.getAdminAddress()); + xxlJobSpringExecutor.setAppname(xxlJobExecutorProp.getAppname()); + + if(xxlJobExecutorProp.getPort() != null){ + xxlJobSpringExecutor.setPort(xxlJobExecutorProp.getPort()); + } + + xxlJobSpringExecutor.setAccessToken(xxlJobExecutorProp.getAccessToken()); + xxlJobSpringExecutor.setLogPath(xxlJobExecutorProp.getLogPath()); + xxlJobSpringExecutor.setLogRetentionDays(xxlJobExecutorProp.getLogretentiondays()); + return xxlJobSpringExecutor; + } + + + @Bean + public ExecutorService executorService() { + return new ThreadPoolExecutor(4, + 4, 1L + , TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), Thread::new, new ThreadPoolExecutor.CallerRunsPolicy()); + } + + + +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/config/SystemYmlConfig.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/config/SystemYmlConfig.java new file mode 100644 index 0000000..9eaf04e --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/config/SystemYmlConfig.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.bill.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 系统Yml配置参数定义Bean + * + * @author terrfly + * @date 2021-04-27 15:50 + */ +@Component +@ConfigurationProperties(prefix="isys") +@Data +public class SystemYmlConfig { + + /** DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] **/ + private String dbEncryptSecret; + + /** 是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. **/ + private Boolean cacheConfig; + +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/mq/ResetIsvMchAppInfoMQReceiver.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/mq/ResetIsvMchAppInfoMQReceiver.java new file mode 100644 index 0000000..495720f --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/mq/ResetIsvMchAppInfoMQReceiver.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.bill.mq; + +import com.jeequan.jeepay.components.mq.model.ResetIsvMchAppInfoConfigMQ; +import com.jeequan.jeepay.core.interfaces.IConfigContextService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 接收MQ消息 + * 业务: 更新服务商/商户/商户应用配置信息; + * + * @author terrfly + * @date 2021/7/27 9:23 + */ +@Slf4j +@Component +public class ResetIsvMchAppInfoMQReceiver implements ResetIsvMchAppInfoConfigMQ.IMQReceiver { + + @Autowired(required = false) + private IConfigContextService configContextService; + + @Override + public void receive(ResetIsvMchAppInfoConfigMQ.MsgPayload payload) { + + if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_ISV_INFO) { + this.modifyIsvInfo(payload.getIsvNo()); + } else if (payload.getResetType() == ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO) { + this.modifyMchInfo(payload.getMchNo()); + } + } + + /** + * 接收 [商户配置信息] 的消息 + **/ + private void modifyMchInfo(String mchNo) { + log.info("成功接收 [商户配置信息] 的消息, msg={}", mchNo); + if (configContextService != null) configContextService.initMchInfoConfigContext(mchNo); + log.info(" [商户配置信息] 已重置"); + } + + /** + * 接收 [商户应用支付参数配置信息] 的消息 + **/ + private void modifyMchApp(String mchNo, String appId) { + log.info("成功接收 [商户应用支付参数配置信息] 的消息, mchNo={}, appId={}", mchNo, appId); + if (configContextService != null) configContextService.initMchAppConfigContext(mchNo, appId); + log.info(" [商户应用支付参数配置信息] 已重置"); + } + + /** + * 重置ISV信息 + **/ + private void modifyIsvInfo(String isvNo) { + log.info("成功接收 [ISV信息] 重置, msg={}", isvNo); + if (configContextService != null) configContextService.initIsvConfigContext(isvNo); + log.info("[ISV信息] 已重置"); + } + +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/service/ReconciliationRestockService.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/service/ReconciliationRestockService.java new file mode 100644 index 0000000..ff8d0c3 --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/service/ReconciliationRestockService.java @@ -0,0 +1,111 @@ +package com.jeequan.jeepay.bill.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.bill.IReconciliationService; +import com.jeequan.jeepay.core.model.bill.ChannelBillRQ; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.CheckBatch; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.service.impl.CheckBatchService; +import com.jeequan.jeepay.service.impl.PayInterfaceConfigService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/*** +* 对账接口 +* +* @author zx +* @date 2022/3/12 14:54 +*/ +@Service +@Slf4j +public class ReconciliationRestockService { + + @Autowired private PayInterfaceConfigService payInterfaceConfigService; + @Autowired private CheckBatchService checkBatchService; + + /** + * 重新对账,解决对账任务中断或某些支付接口账单下载/解析失败问题 + * */ + public void queryChannelBillAndCheck(PayInterfaceDefine payInterfaceDefine, Date billDate) { + + String ifCode = payInterfaceDefine.getIfCode(); + + // 查询去重的渠道商户号 和 本地支付配置 + List channelBillRQList = buildDistinctIfParams(payInterfaceDefine); + if(CollUtil.isEmpty(channelBillRQList)){ + log.info("支付接口:{},无支付参数配置!", ifCode); + return; + } + + // 查询 解析失败&&渠道号 的对账批次 + List checkBatchList = checkBatchService.list(CheckBatch.gw() + .eq(CheckBatch::getIfCode, ifCode) + .eq(CheckBatch::getReleaseState, CS.YES) + .ge(CheckBatch::getBillDate, DateUtil.beginOfDay(billDate)) + .le(CheckBatch::getBillDate, DateUtil.endOfDay(billDate)) + ); + + // 全部 对账解析失败的商户号 + List successChannelMchNoList = checkBatchList.stream().map(CheckBatch::getChannelMchNo).collect(Collectors.toList()); + + // 解析失败的批次重新对账 + for (ChannelBillRQ channelBillRQ : channelBillRQList) { + if (CollUtil.isEmpty(checkBatchList)) { + checkBills4ReleaseFailBatch(ifCode, billDate, channelBillRQ); + continue; + } + + if (!successChannelMchNoList.contains(channelBillRQ.getChannelMchNo())) { + checkBills4ReleaseFailBatch(ifCode, billDate, channelBillRQ); + } + } + + } + + + /** 构建全部服务商、商户的渠道商户号与服务商或应用的配置关系 */ + public List buildDistinctIfParams(PayInterfaceDefine payInterfaceDefine) { + List channelBillRQList = new ArrayList<>(); + if (payInterfaceDefine.getIsIsvMode() != null && payInterfaceDefine.getIsIsvMode() == CS.YES) { + channelBillRQList.addAll(payInterfaceConfigService.selectDistinctIsvIfParams(payInterfaceDefine.getIfCode())); // 查询服务商渠道号 与 服务商号及配置参数对应关系 + channelBillRQList.addAll(payInterfaceConfigService.selectDistinctIsvSubMchIfParams(payInterfaceDefine.getIfCode())); // 查询特约商户 与 商户应用及配置参数对应关系 + }else if (payInterfaceDefine.getIsMchMode() != null && payInterfaceDefine.getIsMchMode() == CS.YES){ + channelBillRQList.addAll(payInterfaceConfigService.selectDistinctNormalMchIfParams(payInterfaceDefine.getIfCode())); // 查询普通商户 与 商户应用及配置参数对应关系 + } + return channelBillRQList; + } + + /** 解析失败的批次 补充对账 */ + public void checkBills4ReleaseFailBatch(String ifCode, Date billDate, ChannelBillRQ channelBillRQ) { + + try { + com.jeequan.jeepay.core.entity.CheckBatch coreCheckBatch = new CheckBatch(); + coreCheckBatch.setBatchNo(checkBatchService.getBatchNo(ifCode, channelBillRQ.getChannelMchNo(), billDate)); + coreCheckBatch.setIfCode(ifCode); + coreCheckBatch.setBillDate(billDate); + coreCheckBatch.setChannelMchNo(channelBillRQ.getChannelMchNo()); + coreCheckBatch.setReleaseState(CS.NO); + + IReconciliationService reconciliationService = SpringBeansUtil.getBean("reconciliationService", IReconciliationService.class); + reconciliationService.reloadBill4Batch(coreCheckBatch, "release"); + + }catch (Exception e) { + log.error("对账单处理失败,支付接口:{},渠道商户号:{},对账日期:{}", ifCode, channelBillRQ.getChannelMchNo(), billDate, e); + } + } + + /** 处理差异 */ + public void processCheckDiffBills(Date billDate) { + IReconciliationService reconciliationService = SpringBeansUtil.getBean("reconciliationService", IReconciliationService.class); + reconciliationService.processCheckDiffBills(billDate); + } +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationRestockTask.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationRestockTask.java new file mode 100644 index 0000000..c9a13fb --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationRestockTask.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.bill.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.jeequan.jeepay.bill.service.ReconciliationRestockService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.service.impl.PayInterfaceDefineService; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * 对账失败的批次 重新跑批 定时任务 + * + * @author zx + * @date 2022/9/9 9:40 + */ +@Slf4j +@Component +public class ReconciliationRestockTask { + + @Autowired private PayInterfaceDefineService payInterfaceDefineService; + @Autowired private ReconciliationRestockService reconciliationRestockService; + + @XxlJob("reconciliationStockTaskHandler") + public void reconciliationStockTask() { + log.info("执行补充对账,开始..."); + + // 对账日期 + Date billDate = DateUtil.beginOfDay(DateUtil.yesterday()); + // Date billDate = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.date(), -3)); + log.info("补充对账日期:{}", DateUtil.formatDate(billDate)); + + // 查询所有支持分账、开启分账的支付接口 + List defineList = payInterfaceDefineService.list(PayInterfaceDefine.gw() + .eq(PayInterfaceDefine::getIsSupportCheckBill, CS.YES) + .eq(PayInterfaceDefine::getIsOpenCheckBill, CS.YES) + ); + if (CollUtil.isEmpty(defineList)) { + log.info("执行补充对账结束。无支付接口支持对账"); + return; + } + + // 遍历支付接口查询渠道对账数据 --> 对账 --> 差异入库 + for (PayInterfaceDefine payInterfaceDefine : defineList) { + reconciliationRestockService.queryChannelBillAndCheck(payInterfaceDefine, billDate); + } + + // 处理差异账单(处理 对账日期前三天内的、本地多帐和渠道多帐情况) + reconciliationRestockService.processCheckDiffBills(billDate); + + log.info("执行补充对账,结束。"); + } + +} diff --git a/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationTask.java b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationTask.java new file mode 100644 index 0000000..f46b608 --- /dev/null +++ b/jeepay-bill/src/main/java/com/jeequan/jeepay/bill/task/ReconciliationTask.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.bill.task; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.bill.IReconciliationService; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.PayInterfaceDefine; +import com.jeequan.jeepay.service.impl.PayInterfaceDefineService; +import com.xxl.job.core.handler.annotation.XxlJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/* + * 对账 定时任务 + * + * @author zx + * @date 2022/9/9 9:40 + */ +@Slf4j +@Component +public class ReconciliationTask { + + @Autowired private PayInterfaceDefineService payInterfaceDefineService; + + @XxlJob("reconciliationTaskHandler") + public void reconciliationTask() { + log.info("执行对账,开始..."); + + // 对账日期 + Date billDate = DateUtil.beginOfDay(DateUtil.yesterday()); + // Date billDate = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.date(), -3)); + log.info("对账日期:{}", DateUtil.formatDate(billDate)); + + // 查询所有支持分账、开启分账的支付接口 + List defineList = payInterfaceDefineService.list(PayInterfaceDefine.gw() + .eq(PayInterfaceDefine::getIsSupportCheckBill, CS.YES) + .eq(PayInterfaceDefine::getIsOpenCheckBill, CS.YES) + ); + if (CollUtil.isEmpty(defineList)) { + log.info("执行对账结束。无支付接口支持对账"); + return; + } + + IReconciliationService reconciliationService = SpringBeansUtil.getBean("reconciliationService", IReconciliationService.class); + + // 遍历支付接口查询渠道对账数据 --> 对账 --> 差异入库 + for (PayInterfaceDefine payInterfaceDefine : defineList) { + reconciliationService.queryChannelBillAndCheck(payInterfaceDefine.getIfCode(), billDate); + } + + // 处理差异账单(处理 对账日期前三天内的、本地多帐和渠道多帐情况) + reconciliationService.processCheckDiffBills(billDate); + + log.info("执行对账,结束。"); + } + +} diff --git a/jeepay-bill/src/main/resources/application-dev.yml b/jeepay-bill/src/main/resources/application-dev.yml new file mode 100644 index 0000000..34fda37 --- /dev/null +++ b/jeepay-bill/src/main/resources/application-dev.yml @@ -0,0 +1,121 @@ +################################# +# spring boot支持外部application.yml 读取优先级为: +# 1、file:./config/(当前目录下的config文件夹) +# 2、file:./(当前目录) +# 3、classpath:/config/(classpath下的config目录) +# 4、classpath:/(classpath根目录) +# 建议: 如果是jar则放置到与jar相同的目录下, 如果解压文件放置到classpath: config目录下。 (需要将文件重命名为 application.yml ) +# +# 该yml文件只配置与环境相关的参数, 其他配置读取项目下的配置项 +# +################################# +# 数据库的配置项, 自定义配置放置在配置顶层 +db-config: + master: #主库配置(必填) + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:mysql://127.0.0.1:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + resources: + static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问) + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + +# #activeMQ配置 ( 注意: activeMQ配置项需在spring的下级 ) + rabbitmq: + addresses: 127.0.0.1:5672 + username: root + password: YinShangFuRabbit@123456 + dynamic: true + virtual-host: / +# +# #rabbitmq配置 ( 注意: rabbitmq配置项需在spring的下级 ) +# rabbitmq: +# addresses: 127.0.0.1:5672 +# username: guest +# password: guest +# dynamic: true +# virtual-host: / + +## rocketmq配置 ( 注意:rocketmq配置项请放置到根目录, 不是spring的二级配置! ) +#rocketmq: +# name-server: 127.0.0.1:9876 +# producer: +# group: JEEPAY-GROUP + +## 阿里云rocketmq配置 ( 注意:aliyun-rocketmq配置项请放置到根目录, 不是spring的二级配置!需要阿里云开通rocketMQ产品,创建Group和Topic ) +#aliyun-rocketmq: +# namesrvAddr: xxx +# accessKey: xxx +# secretKey: xxx +# groupIdPrefix: GID_JEEPAY_ # (分组前缀, 具体名称详见AliyunRocketMQFactory.java ) + + #日志配置参数。 + # 当存在logback-spring.xml文件时: 该配置将引进到logback配置, springboot配置不生效。 + # 不存在logback-spring.xml 文件时, 使用springboot的配置, 同样可用。 +logging: + level: + root: info #主日志级别 + com.jeequan.jeepay: info #该项目日志级别,当需要打印sql时请开启为debug + path: ./bill/logs #日志存放地址 +# xxl-job 执行器配置项 +xxl-job: + executor: + admin-address: http://127.0.0.1:9300/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN + appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + port: 9320 # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能; + + +#系统业务参数 +isys: + + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + + oss: + file-root-path: /home/jeepay/upload #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) + file-private-path: ${isys.oss.file-root-path}/private #私有化本地访问,不允许url方式公共读取 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) + + mq: + vender: rabbitMQ # 切换MQ厂商, 支持:【 activeMQ rabbitMQ rocketMQ aliYunRocketMQ 】, 需正确配置 【对应的yml参数】 和 【jeepay-components-mq项目下pom.xml中的依赖包】。 + diff --git a/jeepay-bill/src/main/resources/application-prod.yml b/jeepay-bill/src/main/resources/application-prod.yml new file mode 100644 index 0000000..fabaa34 --- /dev/null +++ b/jeepay-bill/src/main/resources/application-prod.yml @@ -0,0 +1,114 @@ +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + resources: + static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问) + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + cache: + type: redis + redis: + host: 127.0.0.1 + port: 6379 + timeout: 1000 + password: ax123456ax + activemq: + broker-url: failover:(tcp://127.0.0.1:61616?wireFormat.maxInactivityDuration=0) # + in-memory: false # Jeepay + user: admin # activeMQ + password: 123456 + pool: + enabled: true + max-connections: 10 + idle-timeout: 30000 # +logging: + level: + root: info #主日志级别 +# xxl-job 执行器配置项 +xxl-job: + executor: + admin-address: http://127.0.0.1:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN + # appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + # port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能; + +db-config: + master: #主库配置(必填) + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: yinshangfu + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:p6spy:mysql://rm-bp1c8prh6j399epb5.mysql.rds.aliyuncs.com/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: yinshangfu + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +isys: + #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] + allow-cors: true + + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + # 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! + sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g== + sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + mq: + vender: activeMQ + + oss: + file-root-path: /home/www/.upload #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) diff --git a/jeepay-bill/src/main/resources/application-test.yml b/jeepay-bill/src/main/resources/application-test.yml new file mode 100644 index 0000000..f5b0c3b --- /dev/null +++ b/jeepay-bill/src/main/resources/application-test.yml @@ -0,0 +1,111 @@ +# spring-boot组件配置 +spring: + servlet: + multipart: + enabled: true #是否启用http上传处理 + max-request-size: 10MB #最大请求文件的大小 + max-file-size: 10MB #设置单个文件最大长度 + resources: + static-locations: classpath:/static #项目静态资源路径 (可直接通过http访问) + freemarker: + template-loader-path: classpath:/templates #freemarker模板目录 + template-encoding: UTF-8 + suffix: .ftl + settings: + classic_compatible: true # 如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 + number_format: '#' #数字格式进行原样显示,不加格式化字符例如 100,00 + cache: + type: redis + redis: + host: 47.111.143.211 + port: 6379 + timeout: 1000 + password: ax123456ax + rabbitmq: + addresses: 47.111.143.211:5672 + username: root + password: YinShangFuRabbit@123456 + dynamic: true + virtual-host: / +logging: + level: + root: info #主日志级别 +# xxl-job 执行器配置项 +xxl-job: + executor: + admin-address: http://47.111.143.211:8282/xxl-job-admin # 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册; + access-token: jeepayTaskToken@2022 # 执行器通讯TOKEN + # appname: jeepay-plus-bill-executor # 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册 + # port: # 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口; + log-path: ${logging.file.path} # 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径; + logretentiondays: 7 # 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能; + +db-config: + master: #主库配置(必填) + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + + slave: #从库配置(可选), 若没有显式配置则使用master的配置项。 配置参数与master一致。 + # yml填写url连接串, 无需将&符号进行转义 + url: jdbc:mysql://47.111.143.211:3306/yinshangfu?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: YinShangFuMysql@123456 + encrypt-account: false # 连接账号和密码是否已加密。 true:db的账密需配置密文,函数详见 DBProp.main(); false: db账密请填写明文 + # 连接池配置项 + initial-size: 5 #初始化时建立物理连接的个数 + min-idle: 5 #最小连接池数量 + max-active: 30 #最大连接池数量 + max-wait: 60000 #获取连接时最大等待时间,单位毫秒 + # 检测相关 + test-while-idle: true # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 #连接保持空闲而不被驱逐的最小时间 + validation-query: SELECT 1 FROM DUAL + # 是否缓存preparedStatement + pool-prepared-statements: false # 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 + max-pool-prepared-statement-per-connection-size: 20 # 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。 + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + filters: stat,wall + connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +isys: + #是否允许跨域请求 [生产环境建议关闭, 若api与前端项目没有在同一个域名下时,应开启此配置或在nginx统一配置允许跨域] + allow-cors: true + + db-encrypt-secret: 1234567890123456 #DB SM4 加解密秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + http-message-encrypt-secret: 1234567890123456 #web传输加解密 秘钥 (必须16位) [每个系统配置必须相同,否则加解密不一致导致业务异常!] + + # 支付网关的公钥和私钥(系统级别!), 请妥善保存,用于回调商户的商户侧的验证, 首次设置好之后不可随意变更! + sys-RSA2-private-key: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCLU0lXJu9vcJCwrwFGwT1CqXUSY+JMW2iSRPtgLw6lxjU403hS1VyKxA5uTZokv80Wd+bcxDMrM9DwHeGqhjlWvbB/lqaRliJJRdgLVUedrDY+3YSN75uHBtLmxZbnaUpV6/aWA/a+lkNqHxYCWB1jggFB9DhVg2SgoMGDOYHDNA5ZDl47sKpanW0kfG9lINSV4xgDPmAJxUnhkG/7eVEBDev9EIhc+LIMC7Zj+UYc+s/TK4c31fFTW4dZAp3LVEdct9qXU5qm/fXIXxeo3E0bWyOP3VL4Xmx2S9Host1YzjzXPSi1TJjX7rxQkhmbE/dQJ+ws/VvKPuUpmLEPGsm/AgMBAAECggEBAIONCFq58KoQZw3ssA/WtbkTt+69URc31+0EJTYUOIheNjKJubq8qrx7kgSkUT8RutvUKq+YsZfBPS77h/Ay/EDiqpxN6sjcMVNuFyfcRdqimDWTg21hKEC+OLSdLHcj+4RVYGcVJw2dY9n3sBhWiqlCP12+8tILViA0qYL18YgVYJM3bL2MCXfUnm8/Rn1ut5LuDtU/UuaVz9vuCqNirZJedZx3WEq69ZRt9m44XN934NikbUGxQRlz32WRXDo+ssSTu3174UbDYc8nhqO0jUvuzfjOOMf9NYRJsgqVihxMLvvMaUhEE3w6qZPLMj6KhTiG5QHexBbyLgDxH4TZ4gECgYEAz7vZFMoKYifCi+eFykH/ad8QYYoYLlrU1EN2fpIJqwSHZbpBfB8NM5Ov26xU/aNHGKxtSOrUFva5sWub5f9OlsOAmaUOPuVuaJbsq+e3cNQ41jBcdppGJLNx1p/69zR1rF9TbI9Ambd8sOgX3OZmImA2Ldlk2KvMKRruxwc4uN8CgYEAq7J0u5KTwI3PxENLWQ/6tOBNdbCoyqFM+FdANVHRA4dhhdoJ1x0bpdt3tapPFJTBURSEspNxPl4iT+GdpoF6KwqTsQFmB5TLlfx8wY9SIc+sI/ifZvMA5Dv8vVfYWNig7rGV+vIyJCCNbJ5OMa1xvxTDc7Dx4XPxcJ4sR1ZyqyECgYAe447O8ZADsmfSR9X0EkY5ZurXpiIcWnNFMNbg0TRQ0raTYNO18iQTZEWFA6YLpQjAWXtSmWB6HavU/uxKkeEMt/taXVm17oWxVafRk/4J7/SXnM9S73O4p1opENbPhWRuAiq0fMSdVtRatdg+h5/uQqIrxSSit0D/Z7rTq3Y6vwKBgQCd8AlbJckOHiTZd8GOypkm2xHFydxqkJfZ9YCVy44Fvfnig5/7pcXx+oEStfgKiY+OQt6R2fkYksTjUDmRmZbEkvUqpIuzO5dOf7RO5MR7X6oMaL5QmAXg7KFflrfnelYHW4oIDdQ70UnmeXSaU97HE5V7DXBioCGfI5C9inLuoQKBgQCwJmQ2heyTbG1DIBuqf+GFXLuOp76M/7S9c+5R7yfxyTzAbiKRIPeSF5wlxNXEnGwK7qB9CmctlBdnV7A0qnZVFMXf7AbBDUzOCjiy1RSh04BNPnu0dTIygX2PE5inltrHiZtTgciKwj9MexT97F4mTR76kIMz5SGNZe3PscQr7g== + sys-RSA2-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1NJVybvb3CQsK8BRsE9Qql1EmPiTFtokkT7YC8OpcY1ONN4UtVcisQObk2aJL/NFnfm3MQzKzPQ8B3hqoY5Vr2wf5amkZYiSUXYC1VHnaw2Pt2Eje+bhwbS5sWW52lKVev2lgP2vpZDah8WAlgdY4IBQfQ4VYNkoKDBgzmBwzQOWQ5eO7CqWp1tJHxvZSDUleMYAz5gCcVJ4ZBv+3lRAQ3r/RCIXPiyDAu2Y/lGHPrP0yuHN9XxU1uHWQKdy1RHXLfal1Oapv31yF8XqNxNG1sjj91S+F5sdkvR6LLdWM481z0otUyY1+68UJIZmxP3UCfsLP1byj7lKZixDxrJvwIDAQAB + + #是否内存缓存配置信息: true表示开启如支付网关地址/商户应用配置/服务商配置等, 开启后需检查MQ的广播模式是否正常; false表示直接查询DB. + cache-config: false + mq: + vender: rabbitMQ + + oss: + file-root-path: D:/jeepayFiles #存储根路径 ( 无需以‘/’结尾 ) + file-public-path: ${isys.oss.file-root-path}/public #公共读取块 ( 一般配合root-path参数进行设置,需以‘/’ 开头, 无需以‘/’结尾 ) diff --git a/jeepay-bill/src/main/resources/application.yml b/jeepay-bill/src/main/resources/application.yml new file mode 100644 index 0000000..135f665 --- /dev/null +++ b/jeepay-bill/src/main/resources/application.yml @@ -0,0 +1,7 @@ +server: + port: 9220 #设置端口 + servlet: + context-path: / #设置应用的目录. 前缀需要带/, 无需设置后缀, 示例 【 /xxx 】 or 【 / 】 +spring: + profiles: + active: dev \ No newline at end of file diff --git a/jeepay-bill/src/main/resources/banner.txt b/jeepay-bill/src/main/resources/banner.txt new file mode 100644 index 0000000..2b3be6c --- /dev/null +++ b/jeepay-bill/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + __ + / /___ ___ ____ ____ ___ __ + __ / // _ \/ _ \/ __ \/ __ `/ / / / +/ /_/ // __/ __/ /_/ / /_/ / /_/ / +\____/ \___/\___/ .___/\__,_/\__, / + /_/ /____/ + :: Jeepay Plus :: (v2.9.1.RELEASE) diff --git a/jeepay-bill/src/main/resources/logback-spring.xml b/jeepay-bill/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..a5ad4cb --- /dev/null +++ b/jeepay-bill/src/main/resources/logback-spring.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + ${currentLoggerPattern} + + + + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.all.log + + ${currentLoggerPattern} + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.all.%d{yyyy-MM-dd}.log + 5 + + + + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.error.log + + ${currentLoggerPattern} + + + + ${currentLoggerFilePath}/${currentLoggerFileName}.error.%d{yyyy-MM-dd}.log + 20 + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + diff --git a/jeepay-components/jeepay-components-3rd/pom.xml b/jeepay-components/jeepay-components-3rd/pom.xml new file mode 100644 index 0000000..36b9ef1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/pom.xml @@ -0,0 +1,257 @@ + + + 4.0.0 + + com.jeequan + jeepay-components-3rd + jar + ${isys.version} + Jeepay计全支付系统 [三方调用接口] + https://www.jeequan.com + + + com.jeequan + jeepay-components + Final + + + + + ${basedir}/../../ + + + + + + + + com.jeequan + jeepay-components-db + + + + com.bill99 + crypto-sdk + + + + + com.jeequan + jeepay-components-oss + + + + net.coobird + thumbnailator + 0.4.14 + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + org.springframework.boot + spring-boot-starter-web + provided + + + + + org.springframework.boot + spring-boot-starter-data-redis + provided + + + + + org.hibernate.validator + hibernate-validator + + + + + com.github.binarywang + weixin-java-pay + + + + com.github.binarywang + weixin-java-mp + + + + com.github.binarywang + weixin-java-miniapp + + + + + + com.huifu.adapay.core + adapay-core-sdk + 1.2.10 + + + + + com.huifu.adapay + adapay-java-sdk + 1.2.10 + + + + + com.paypal.sdk + checkout-sdk + 1.0.5 + + + + + com.google.zxing + core + + + com.google.zxing + javase + + + + + com.alipay.sdk + alipay-sdk-java + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.2 + + + + + com.aliyun + ocr_api20210707 + 1.1.1 + + + + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.322 + + + + + com.getui.push + restful-sdk + 1.0.0.4 + + + + + cn.com.sand + sandpay-hmpay-sdk + + + + + commons-net + commons-net + 3.6 + + + com.jcraft + jsch + 0.1.54 + + + + + cfca.sadk + cfca-sadk + + + + cfca.logback + cfca-logback + + + + hikefa.core + yspay-hikefa + + + + + org.bouncycastle + bcprov-jdk15on + 1.61 + + + + com.payermax + payermax-server-sdk + 1.0.3 + + + + + ccbpay.netpay + ccbpay-netpay + + + + + com.alipay.bpaas + bpaas-bizapi-sdk + + + + + com.bocom.api + bocom-openapi-sdk + + + + + com.icbc + icbc-api-sdk-cop + + + com.icbc.api + icbc-api-sdk-cop-io + + + cn.com.infosec + icbc-ca + + + com.icbc + hsm-software-share + + + com.clj + leshuapay-sdk + + + + com.jeequan + jeepay-components-core + + + + + + + ${project.artifactId} + + + + diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbsIsvmchWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbsIsvmchWrapper.java new file mode 100644 index 0000000..8fc0abb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbsIsvmchWrapper.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWrapper; +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.db.entity.MchAppEntity; +import com.jeequan.jeepay.db.entity.RateConfig; +import com.jeequan.jeepay.service.impl.MchAppService; +import com.jeequan.jeepay.service.impl.RateConfigService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public abstract class AbsIsvmchWrapper implements IIsvmchWrapper { + + @Autowired + private RateConfigService rateConfigService; + + @Autowired + private MchAppService mchAppService; + + /** + * 根据商户的上下级设置其缺省的费率值 + * + * @param mchApplyment 商户信息 + */ + @Override + public final void rateWrap(MchApplyment mchApplyment) { + JSONObject applyDetailInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo()); + + Map mchApplyRateConfigMap = new HashMap<>(); + Optional.ofNullable(applyDetailInfo.getJSONArray("paywayFeeList")) + .map(t -> t.toJavaList(PaywayFee.class)) + .map(t -> { + t.forEach(t2 -> mchApplyRateConfigMap.put(t2.getWayCode(), t2)); + return t; + }); + + MchAppEntity mchApp = mchAppService.getById(mchApplyment.getAutoConfigMchAppId()); + + String agentNo = mchApplyment.getAgentNo(); + String isvNo = mchApplyment.getIsvNo(); + + // 获取商户费率, 一般来说这一步是没必要的,这里单纯做数据初始化吧 + Map mchRateConfigMap = rateConfigService.queryPaywayFeeMap(agentNo + "_" + RateConfig.MCHRATE, CS.SYS_ROLE_TYPE.MCH_APP, mchApplyment.getIfCode() + , mchApp.getRange(), mchApp.getMccCode(), mchApplyment.getIsvNo()); + setIfEmpty(mchApplyRateConfigMap, mchRateConfigMap); + + // 获取直属上级费率 + Map agentMchDefRateConfigMap = rateConfigService.queryPaywayFeeMap(agentNo + "_" + RateConfig.MCHAPPLYDEF, CS.SYS_ROLE_TYPE.AGENT, mchApplyment.getIfCode() + , mchApp.getRange(), mchApp.getMccCode(), mchApplyment.getIsvNo()); + setIfEmpty(mchRateConfigMap, agentMchDefRateConfigMap); + + // 获取服务商费率信息 + Map isvRateConfigMap = rateConfigService.queryPaywayFeeMap(isvNo + "_" + RateConfig.MCHAPPLYDEF, CS.SYS_ROLE_TYPE.ISV, mchApplyment.getIfCode() + , mchApp.getRange(), mchApp.getMccCode(), mchApplyment.getIsvNo()); + setIfEmpty(mchRateConfigMap, isvRateConfigMap); + + mchRateConfigMap = channelInit(mchRateConfigMap, mchApplyment); + + applyDetailInfo.put("paywayFeeList", mchRateConfigMap.values()); + + mchApplyment.setApplyDetailInfo(JSON.toJSONString(applyDetailInfo)); + } + + private void setIfEmpty(Map mchRate, Map targetConfigMap) { + targetConfigMap.forEach((wayCode, rateConfig) -> mchRate.putIfAbsent(wayCode, targetConfigMap.get(wayCode))); + } + + public Map channelInit(Map mchRateConfigMap, MchApplyment mchApplyment) { + return mchRateConfigMap; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractBillDownloadService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractBillDownloadService.java new file mode 100644 index 0000000..5a384c2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractBillDownloadService.java @@ -0,0 +1,76 @@ +package com.jeequan.jeepay.thirdparty.channel; + + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.jeequan.jeepay.components.oss.ctrl.OssFileController; +import com.jeequan.jeepay.components.oss.model.MockMultipartFile; +import com.jeequan.jeepay.components.oss.model.OssFileConfig; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.CheckBatch; +import com.jeequan.jeepay.core.interfaces.paychannel.IBillDownloadService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.Date; + +/* +* 渠道对账单下载 抽象类 +* +* @author zx +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractBillDownloadService implements IBillDownloadService { + + @Autowired protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + @Autowired private OssFileController ossFileController; + + + // 上传文件至oss + public String upload2Oss(String ifCode, String channelMchNo, Date billDate, String suffix, InputStream inputStream){ + return ossFileController.singleFileUpload(new MockMultipartFile(genOssFileName(ifCode, channelMchNo, billDate, suffix), 1L, inputStream), OssFileConfig.BIZ_TYPE.CHANNEL_BILL); + } + + // 生成上传oss 账单文件名称、后缀 + public String genOssFileName(String ifCode, String channelMchNo, Date billDate, String suffix){ + return String.format("%s_%s_%s_%s", ifCode, channelMchNo, DateUtil.format(billDate, DatePattern.PURE_DATE_PATTERN), suffix); + } + + /** 生成渠道账单 解析成功 的对账批次 */ + public CheckBatch genReleaseSuccessCheckBatch(String ifCode, Date billDate, String channelMchNo, String path) { + return initCheckBatch(ifCode, billDate, channelMchNo, path, CS.YES, null); + } + + /** 生成渠道账单 解析失败 的对账批次 */ + public CheckBatch genReleaseFailCheckBatch(String ifCode, Date billDate, String channelMchNo, String releaseErrMsg) { + return initCheckBatch(ifCode, billDate, channelMchNo, null, CS.NO, releaseErrMsg); + } + + /** 初始化对账批次 */ + public CheckBatch initCheckBatch(String ifCode, Date billDate, String channelMchNo, String path, Byte releaseState, String releaseErrMsg) { + CheckBatch checkBatch = new CheckBatch(); + checkBatch.setBatchNo(getBatchNo(ifCode, channelMchNo, billDate)); + checkBatch.setIfCode(ifCode); + checkBatch.setBillDate(billDate); + checkBatch.setChannelMchNo(channelMchNo); + checkBatch.setState(CS.NO); //未处理状态 + checkBatch.setOrgBillFilePath(path); + checkBatch.setReleaseState(releaseState); + checkBatch.setReleaseErrMsg(releaseErrMsg); + checkBatch.setChannelTotalAmount(BigDecimal.ZERO.longValue()); + return checkBatch; + } + + // 对账批次号 支付接口代码ifCode_渠道商户号_对账日期 + public String getBatchNo(String ifCode, String channelMchNo, Date billDate) { + return ifCode + "_" + channelMchNo + "_" + DateUtil.format(billDate, DatePattern.PURE_DATE_PATTERN); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelAccountService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelAccountService.java new file mode 100644 index 0000000..479b2f1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelAccountService.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.thirdparty.channel; + + +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelAccountService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; + +/* +* 提现接口抽象类 +* +* @author zx +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractChannelAccountService implements IChannelAccountService { + + @Autowired protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + + protected String getPaySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + protected String getNotifyUrl(){ + return getPaySiteUrl() + "/api/channel/cashout/notify/" + getIfCode(); + } + + protected String getNotifyUrl(String rid){ + return getPaySiteUrl() + "/api/channel/cashout/notify/" + getIfCode() + "/" + rid; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelCashoutNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelCashoutNoticeService.java new file mode 100644 index 0000000..898e728 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelCashoutNoticeService.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.cashout.IChannelCashoutNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.File; + +/* +* 实现提现回调接口抽象类 +* +* @author zx +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractChannelCashoutNoticeService implements IChannelCashoutNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelNoticeService.java new file mode 100644 index 0000000..a5fd856 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelNoticeService.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; + +/* +* 实现回调接口抽象类 +* +* @author terrfly +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractChannelNoticeService implements IChannelNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) { + return textResp("order not exists"); + } + + @Override + public ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request) { + return textResp("update status error"); + } + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelOrderAcceptService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelOrderAcceptService.java new file mode 100644 index 0000000..78e2035 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelOrderAcceptService.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelOrderAcceptService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.File; + +/* +* 实现回调接口抽象类 +* +* @author terrfly +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractChannelOrderAcceptService implements IChannelOrderAcceptService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelRefundNoticeService.java new file mode 100644 index 0000000..1d9f900 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractChannelRefundNoticeService.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; + +/* +* 实现退款回调接口抽象类 +* +* @author jmdhappy +* +* @date 2021/9/25 23:18 +*/ +public abstract class AbstractChannelRefundNoticeService implements IChannelRefundNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) { + return textResp("order not exists"); + } + + @Override + public ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request) { + return textResp("update status error"); + } + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionRecordChannelNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionRecordChannelNotifyService.java new file mode 100644 index 0000000..c42c4f9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionRecordChannelNotifyService.java @@ -0,0 +1,95 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.DivisionChannelNotifyModel; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.util.List; + +/* +* 分账结果回调接口抽象类 +* +* @author terrfly +* +* @date 2023/3/29 15:39 +*/ +public abstract class AbstractDivisionRecordChannelNotifyService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + + /** 获取到接口code **/ + public abstract String getIfCode(); + + /** 解析参数: 批次号 和 请求参数 + * 异常需要自行捕捉,并返回null , 表示已响应数据。 + * **/ + public abstract MutablePair parseParams(HttpServletRequest request); + + /** + * 返回需要更新的记录 状态 和响应数据 + * + * **/ + public abstract DivisionChannelNotifyModel doNotify(HttpServletRequest request, Object params, + List recordList, MchAppConfigContext mchAppConfigContext); + + public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) { + return textResp("order not exists"); + } + + public ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request) { + return textResp("update status error"); + } + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionService.java new file mode 100644 index 0000000..babe607 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractDivisionService.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel; + + +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IDivisionService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.List; + +/** +* abstract 分账实现 +* +* @author terrfly +* +* @date 2022/6/13 11:09 +*/ +public abstract class AbstractDivisionService implements IDivisionService { + + @Autowired + protected SysConfigService sysConfigService; + + protected String getPaySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + @Override + public String getIfCode(MchDivisionReceiver mchDivisionReceiver) { + return mchDivisionReceiver.getIfCode(); + } + + @Override + public String getIfCode(PayOrder payOrder) { + return payOrder.getIfCode(); + } + + @Override + public String getIfCode(PayOrderDivisionRecord payOrderDivisionRecord) { + return payOrderDivisionRecord.getIfCode(); + } + + @Override + public boolean divisionRefundIsOrderRefundAfterProc() { + return false; // 默认分账业务前发起退分处理。 + } + + @Override + public HashMap queryDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext){ + throw new BizException("接口不支持"); + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + @Override + public String divisionFinishAfterDivision(PayOrderDivisionRecord divisionRecord, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + protected String getNotifyUrl(){ + return getPaySiteUrl() + "/api/divisionRecordChannelNotify/" + getIfCode(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApiService.java new file mode 100644 index 0000000..f678f20 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApiService.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IMchApiService; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.rqrs.settle.ChannelSettleRq; + +/** + * TODO + * + * @author crystal + * @date 2023/12/4 10:46 + */ +public abstract class AbstractMchApiService implements IMchApiService { + + /** + * 通用结算参数校验 + * @param settleRq + */ + protected void preSettleCheck(ChannelSettleRq settleRq){ + if(settleRq.getPage() == null){ + throw new BizException("当前页不能为空"); + } + if(settleRq.getSize() == null){ + throw new BizException("每页显示的条数不能为空"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApplymentNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApplymentNoticeService.java new file mode 100644 index 0000000..d86a9a6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractMchApplymentNoticeService.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchStoreApplymentNotifyService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.File; + +/** + * 实现回调接口抽象类 + * + * @author xiaoyu + * + * @date 2022/3/26 18:21 + */ +public abstract class AbstractMchApplymentNoticeService implements IIsvmchStoreApplymentNotifyService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPaymentService.java new file mode 100644 index 0000000..01d5a18 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPaymentService.java @@ -0,0 +1,120 @@ +package com.jeequan.jeepay.thirdparty.channel; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPaymentService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.terminal.TerminalChannelModel; +import com.jeequan.jeepay.db.entity.MchStoreTerminal; +import com.jeequan.jeepay.service.impl.MchStoreTerminalService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +/* +* 支付接口抽象类 +* +* @author terrfly +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractPaymentService implements IPaymentService { + + @Autowired protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + @Autowired private MchStoreTerminalService mchStoreTerminalService; + + @Override + public String getIfCode(PayOrder payOrder) { + return payOrder.getIfCode(); + } + + /** 订单分账(一般用作 如微信订单将在下单处做标记) */ + protected boolean isDivisionOrder(PayOrder payOrder){ + //订单分账, 将冻结商户资金。 + if(payOrder.getDivisionMode() != null && (PayOrder.DIVISION_MODE_AUTO == payOrder.getDivisionMode() || PayOrder.DIVISION_MODE_MANUAL == payOrder.getDivisionMode() )){ + return true; + } + return false; + } + + protected String getPaySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + protected String getNotifyUrl(){ + return getPaySiteUrl() + "/api/pay/notify/" + getIfCode(); + } + + protected String getNotifyUrl(String payOrderId){ + return getPaySiteUrl() + "/api/pay/notify/" + getIfCode() + "/" + payOrderId; + } + + protected String getNotifyUrlByFixMchApp(String mchAppId){ + return getPaySiteUrl() + "/api/pay/notify/" + getIfCode() + "/" + CS.PAY_RETURNURL_FIX_MCHAPP_PREFIX + mchAppId; + } + + protected String getPosNotifyUrl(){ + return getPaySiteUrl() + "/api/pos/pay/notify/" + getIfCode(); + } + + protected String getReturnUrl(){ + return getPaySiteUrl() + "/api/pay/return/" + getIfCode(); + } + + protected String getReturnUrl(String payOrderId){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/pay/return/" + getIfCode() + "/" + payOrderId; + } + + protected String getReturnUrlOnlyJump(String payOrderId){ + return getPaySiteUrl() + "/api/pay/return/" + getIfCode() + "/" + CS.PAY_RETURNURL_FIX_ONLY_JUMP_PREFIX + payOrderId; + } + + + /** + * 查找出对应的设备信息 + * + * @author terrfly + * + * @date 2022/4/29 15:20 + */ + protected String queryStoreTerminalChannelTrmNo(String trmNo, PayOrder payOrder){ + + MchStoreTerminal mchStoreTerminal = null; + + LambdaQueryWrapper lambdaQueryWrapper = MchStoreTerminal.gw() + .eq(MchStoreTerminal::getMchNo, payOrder.getMchNo()) + .eq(MchStoreTerminal::getAppId, payOrder.getAppId()) + .eq(MchStoreTerminal::getStoreId, payOrder.getStoreId()) + .eq(MchStoreTerminal::getState, CS.YES); + + // 指定编号查询 + if(StringUtils.isNotEmpty(trmNo)){ + + lambdaQueryWrapper.eq(MchStoreTerminal::getTrmNo, trmNo); + }else{ // 查询默认 + lambdaQueryWrapper .eq(MchStoreTerminal::getDefaultFlag, CS.YES); + } + + mchStoreTerminal = mchStoreTerminalService.getOne(lambdaQueryWrapper,false); + if(mchStoreTerminal == null || mchStoreTerminal.getChannelBindInfo() == null){ + return null; + } + + TerminalChannelModel model = mchStoreTerminal.getChannelBindInfo().getObject(payOrder.getIfCode(), TerminalChannelModel.class); + + if(model != null && model.getState() != null && model.getState() == TerminalChannelModel.STATE_SUCCESS && StringUtils.isNotEmpty(model.getChannelTrmNo())){ + + return model.getChannelTrmNo(); + } + + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPosNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPosNoticeService.java new file mode 100644 index 0000000..51ddf9f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractPosNoticeService.java @@ -0,0 +1,55 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IPosNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +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 17:18 +*/ +public abstract class AbstractPosNoticeService implements IPosNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRefundService.java new file mode 100644 index 0000000..4367352 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRefundService.java @@ -0,0 +1,115 @@ +package com.jeequan.jeepay.thirdparty.channel; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IRefundService; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRefundLimit; +import com.jeequan.jeepay.core.model.terminal.TerminalChannelModel; +import com.jeequan.jeepay.db.entity.AccountInfo; +import com.jeequan.jeepay.db.entity.MchStoreTerminal; +import com.jeequan.jeepay.service.impl.AccountInfoService; +import com.jeequan.jeepay.service.impl.MchStoreTerminalService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +/* +* 退款接口抽象类 +* +* @author terrfly +* +* @date 2021/6/17 9:37 +*/ +public abstract class AbstractRefundService implements IRefundService { + + @Autowired protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + @Autowired private MchStoreTerminalService mchStoreTerminalService; + @Autowired protected AccountInfoService accountInfoService; + + @Override + public String getIfCode(RefundOrder refundOrder) { + return refundOrder.getIfCode(); + } + + protected String getNotifyUrl(){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode(); + } + + protected String getNotifyUrl(String refundOrderId){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode() + "/" + refundOrderId; + } + + protected String getPosNotifyUrl(){ + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/pos/pay/notify/" + getIfCode(); + } + + /** + * 查找出对应的设备信息 + * + * @author terrfly + * + * @date 2022/4/29 15:20 + */ + protected String queryStoreTerminalChannelTrmNo(String trmNo, PayOrder payOrder){ + + MchStoreTerminal mchStoreTerminal = null; + + LambdaQueryWrapper lambdaQueryWrapper = MchStoreTerminal.gw() + .eq(MchStoreTerminal::getMchNo, payOrder.getMchNo()) + .eq(MchStoreTerminal::getAppId, payOrder.getAppId()) + .eq(MchStoreTerminal::getStoreId, payOrder.getStoreId()) + .eq(MchStoreTerminal::getState, CS.YES); + + // 指定编号查询 + if(StringUtils.isNotEmpty(trmNo)){ + + lambdaQueryWrapper.eq(MchStoreTerminal::getTrmNo, trmNo); + }else{ // 查询默认 + lambdaQueryWrapper .eq(MchStoreTerminal::getDefaultFlag, CS.YES); + } + + mchStoreTerminal = mchStoreTerminalService.getOne(lambdaQueryWrapper,false); + if(mchStoreTerminal == null || mchStoreTerminal.getChannelBindInfo() == null){ + return null; + } + + TerminalChannelModel model = mchStoreTerminal.getChannelBindInfo().getObject(getIfCode(), TerminalChannelModel.class); + + if(model != null && model.getState() != null && model.getState() == TerminalChannelModel.STATE_SUCCESS && StringUtils.isNotEmpty(model.getChannelTrmNo())){ + + return model.getChannelTrmNo(); + } + + return null; + } + + /** + * 退款权限判断 + * @param settleType + * @param applyId + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId){ + ChannelRefundLimit refundLimit = new ChannelRefundLimit(false,true); + return refundLimit; + } + + /** + * 校验平台账户余额 + * @param refundOrder + */ + @Override + public void checkPlatAccount(RefundOrder refundOrder){ + if(RefundOrder.REFUND_ACCOUNT_PLAT.equals(refundOrder.getExtParam())){ + accountInfoService.checkBalance(refundOrder.getMchNo(), AccountInfo.Type.REFUND,refundOrder.getRefundAmount()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayApiService.java new file mode 100644 index 0000000..b27767a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayApiService.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IRepayApiService; +import com.jeequan.jeepay.core.model.df.Account; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * TODO + * + * @author crystal + * @date 2024/3/25 10:43 + */ +public abstract class AbstractRepayApiService implements IRepayApiService { + + @Autowired + protected SysConfigService sysConfigService; + @Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + protected String getPaySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + protected String getNotifyUrl(){ + return getPaySiteUrl() + "/api/channel/payment/notify/" + getIfCode(); + } + + /** + * 校验账户余额 + * @param mchNo + * @param accountType + * @param changeAmt + */ + @Override + public void checkAccountBalance(String mchNo,byte accountType, Long changeAmt) { + Account account = this.queryAccountBalance(mchNo, accountType); + if(account.getBalance() < changeAmt){ + throw new BizException("账户不足,请先在后台充值后再操作"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayNoticeService.java new file mode 100644 index 0000000..db6bad7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractRepayNoticeService.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.IRepayNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.File; + +/* +* 实现回调接口抽象类 +* +* @author terrfly +* +* @date 2021/6/8 17:18 +*/ +public abstract class AbstractRepayNoticeService implements IRepayNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferNoticeService.java new file mode 100644 index 0000000..ae5028f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferNoticeService.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.interfaces.paychannel.ITransferNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; + +/* +* 实现回调接口抽象类 +* +* @author zx +* +* @date 2022/12/30 10:18 +*/ +public abstract class AbstractTransferNoticeService implements ITransferNoticeService { + + @Autowired private RequestKitBean requestKitBean; + @Autowired private ChannelCertConfigKitBean channelCertConfigKitBean; + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) { + return textResp("order not exists"); + } + + /** 文本类型的响应数据 **/ + protected ResponseEntity textResp(String text){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + /** json类型的响应数据 **/ + protected ResponseEntity jsonResp(Object body){ + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + return new ResponseEntity(body, httpHeaders, HttpStatus.OK); + } + + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected JSONObject getReqParamJSON() { + return requestKitBean.getReqParamJSON(); + } + + /**request.getParameter 获取参数 并转换为JSON格式 **/ + protected String getReqParamFromBody() { + return requestKitBean.getReqParamFromBody(); + } + + /** 获取文件路径 **/ + protected String getCertFilePath(String certFilePath) { + return channelCertConfigKitBean.getCertFilePath(certFilePath); + } + + /** 获取文件File对象 **/ + protected File getCertFile(String certFilePath) { + return channelCertConfigKitBean.getCertFile(certFilePath); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferService.java new file mode 100644 index 0000000..9138b67 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/AbstractTransferService.java @@ -0,0 +1,189 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import cn.hutool.core.date.DateField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.AccountOperate; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferWallet; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.ITransferService; +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.AccountFundInfo; +import com.jeequan.jeepay.db.entity.AccountInfo; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.db.entity.TransferWalletEntity; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; + +/** + * 支付接口抽象类 + * + * @author terrfly + * + * @since 2021/6/8 17:18 + */ +public abstract class AbstractTransferService implements ITransferService { + + @Autowired protected TransferOrderService transferOrderService; + + @Autowired protected TransferWalletService transferWalletService; + + @Autowired protected TransferSubjectService transferSubjectService; + + @Autowired protected SysConfigService sysConfigService; + + @Autowired protected AccountInfoService accountInfoService; + + protected String getPaySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + protected String getNotifyUrl(){ + return getPaySiteUrl() + "/api/transfer/notify/" + getIfCode(); + } + + protected String getNotifyUrl(String payOrderId){ + return getPaySiteUrl() + "/api/transfer/notify/" + getIfCode() + "/" + payOrderId; + } + + @Override + public MutablePair queryBalanceAmount(TransferWallet transferWallet) {; + return MutablePair.of(null, null); + } + + @Override + public String preCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + commonCheck(bizRQ, transferOrder); + + return ""; + } + + @Override + public void commonCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + checkAmountLimit(bizRQ, transferOrder); + checkRateAccountFee(bizRQ, transferOrder); + } + + /** + * 交易限额的校验 + */ + protected final void checkAmountLimit(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + String transferSubjectIdFq = transferOrder.getTransferSubjectIdFq(); + TransferWalletEntity transferWallet = transferWalletService.getByApplyId(transferSubjectIdFq, null); + + Long monthLimit; + Long dayLimit; + + String transferTypeName; + switch (transferOrder.getEntryType()) { + case TransferOrder.ENTRY_BANK_CARD: + if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) { + transferTypeName = "对公账户"; + // 对公 + if (transferOrder.getAmount() > transferWallet.getBankCardCorOnceMax()) { + throw new BizException("转账单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getBankCardCorOnceMax()) + "]"); + } + } else { + transferTypeName = "个人银行卡"; + // 对私 + if (transferOrder.getAmount() > transferWallet.getBankCardPriOnceMax()) { + throw new BizException("转账个人银行卡单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getBankCardPriOnceMax()) + "]"); + } + } + + monthLimit = transferWallet.getBankCardMonthMax(); + dayLimit = transferWallet.getBankCardDayMax(); + break; + case TransferOrder.ENTRY_WX_CASH: + if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) { + transferTypeName = "企业微信"; + // 企业微信 + if (transferOrder.getAmount() > transferWallet.getWxCorOnceMax()) { + throw new BizException("转账企业微信单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getWxCorOnceMax()) + "]"); + } + } else { + transferTypeName = "个人微信"; + // 对私 + if (transferOrder.getAmount() > transferWallet.getWxPriOnceMax()) { + throw new BizException("转账个人微信单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getWxPriOnceMax()) + "]"); + } + } + + monthLimit = transferWallet.getWxMonthMax(); + dayLimit = transferWallet.getWxDayMax(); + break; + case TransferOrder.ENTRY_ALIPAY_CASH: + if (transferOrder.getAccountType().equals(TransferBasicInfo.ACCOUNT_TYPE_COR)) { + transferTypeName = "企业支付宝"; + // 对公 + if (transferOrder.getAmount() > transferWallet.getZfbCorOnceMax()) { + throw new BizException("转账企业支付宝单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getZfbCorOnceMax()) + "]"); + } + } else { + transferTypeName = "个人支付宝"; + // 对私 + if (transferOrder.getAmount() > transferWallet.getZfbPriOnceMax()) { + throw new BizException("转账个人支付宝单笔超限额[" + AmountUtil.convertCent2Dollar(transferWallet.getZfbPriOnceMax()) + "]"); + } + } + + monthLimit = transferWallet.getZfbMonthMax(); + dayLimit = transferWallet.getZfbDayMax(); + break; + default: + throw new BizException("未知的打款方式"); + } + + Date current = new Date(); + Long accumulatedMonth = transferOrderService.accumulated(DateField.MONTH, current, + TransferOrder.TRANSFER_TYPE_OUT, transferOrder.getEntryType(), transferSubjectIdFq, + TransferOrder.STATE_INIT, TransferOrder.STATE_ING, TransferOrder.STATE_SUCCESS); + + if (accumulatedMonth + transferOrder.getAmount() > monthLimit) {; + throw new BizException("操作失败,转账" + transferTypeName + "已达到月限额[" + monthLimit + "]"); + } + + Long accumulatedDay = transferOrderService.accumulated(DateField.DAY_OF_YEAR, current, + TransferOrder.TRANSFER_TYPE_OUT, transferOrder.getEntryType(), transferSubjectIdFq, + TransferOrder.STATE_INIT, TransferOrder.STATE_ING, TransferOrder.STATE_SUCCESS); + + if (accumulatedDay + transferOrder.getAmount() > dayLimit) { + throw new BizException("操作失败,转账" + transferTypeName + "已达到日限额[" + dayLimit + "]"); + } + } + + /** + * 手续费校验 + */ + protected final void checkRateAccountFee(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + // 手续费外扣,需要校验余额 + if (transferOrder.getFeeCostType().equals(TransferOrder.COST_TYPE_ACCOUNT)) { + // 校验余额, + TransferSubjectEntity transferSubject = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + String infoId; + if (transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.MCH)) { + infoId = transferSubject.getMchNo(); + } else { + infoId = transferSubject.getAgentNo(); + } + + AccountInfo accountInfo = accountInfoService.getAccountInfo(infoId, AccountInfo.Type.SERVICE_CHARGE.getType()); + if (accountInfo.getBalacne() < transferOrder.getMchOrderFeeAmount()) { + throw new BizException("当前手续费余额不足"); + } + + // 预扣手续费 + AccountOperate accountOperate = new AccountOperate(accountInfo.getAccountNo(), transferOrder.getAmount(), + AccountFundInfo.ChangeType.TRANSFER.getValue(), AccountFundInfo.ChangeMethod.DF.getValue(), + transferOrder.getTransferId(), "代付手续费"); + accountOperate.setFinalAmt(transferOrder.getMchOrderFeeAmount()); + accountOperate.setIsUpdateAccount(true); + accountInfoService.upAccount(accountOperate); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/IsvFactory.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/IsvFactory.java new file mode 100644 index 0000000..3d82991 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/IsvFactory.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.thirdparty.channel; + +import com.jeequan.jeepay.core.interfaces.paychannel.*; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * 返回各个通道的的 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class IsvFactory { + public static IIsvmchApplymentService getIsvMchApplymentService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "MchApplymentService", IIsvmchApplymentService.class); + } + + public static IIsvmchWxConfigService getIsvMchWxConfigService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "IsvmchWxConfigService", IIsvmchWxConfigService.class); + } + + public static IIsvmchAlipayConfigService getIsvMchAlipayConfigService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "IsvmchAlipayConfigService", IIsvmchAlipayConfigService.class); + } + + public static IIsvmchModifyApplymentService getIsvMchModifyApplymentService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "IsvmchModifyApplymentService", IIsvmchModifyApplymentService.class); + } + + public static IGetApplymentDataService getGetApplymentDataService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "GetApplymentDataService", IGetApplymentDataService.class); + } + + public static IIsvmchWrapper getIsvMchWrapper(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "IsvmchWrapper", IIsvmchWrapper.class); + } + + public static ITransferService getTransferService(String ifCode) { + return SpringBeansUtil.getBean(ifCode + "TransferService", ITransferService.class); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfChannelTransferSubjectService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfChannelTransferSubjectService.java new file mode 100644 index 0000000..3fd5f6f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfChannelTransferSubjectService.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.thirdparty.channel.aliaqf; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.transfer.IChannelTransferSubjectService; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.service.impl.TransferSubjectService; +import com.jeequan.jeepay.thirdparty.channel.aliaqf.model.AliAqfTransferBasicInfo; +import com.jeequan.jeepay.thirdparty.channel.alipay.AliAqfV2Service; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * TODO + * + * @author deng + * @since 2024/5/8 + */ +@Slf4j +@Service +public class AliaqfChannelTransferSubjectService implements IChannelTransferSubjectService { + + @Autowired + private TransferSubjectService transferSubjectService; + + @Autowired + private AliAqfV2Service aliAqfV2Service; + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public void addExporter(AliAqfTransferBasicInfo transferBasicInfo) { + + } + + @Override + public void addAcceptor(AliAqfTransferBasicInfo transferBasicInfo) { + throw new BizException("当前通道【安全发】不支持该操作"); + } + + @Override + public void callbackProcess(JSONObject bizContent) { + log.info("安全发的签约回调, 回调参数为{}", bizContent); + TransferSubjectEntity subjectEntity = transferSubjectService.getByApplyId(bizContent.getString("external_agreement_no")); + + AliaqfIsvParams isvParams = (AliaqfIsvParams) configContextQueryService.queryTransferIsvParams(subjectEntity.getIsvNo(), CS.IF_CODE.ALIAQF); + try { + //验签 + if (!AliaqfKit.checkSign(bizContent, isvParams)) { + log.error("安全发签约回调验签失败"); + return; + } + + subjectEntity.setTransChannelSignNo(bizContent.getString("agreement_no")); + subjectEntity.setSuccResParameter(bizContent.toJSONString()); + + switch (bizContent.getString("status")) { + case "NORMAL": + subjectEntity.setSignState((int) TransferSubject.SIGN_STATE_SUCCESS); + transferSubjectService.updateById(subjectEntity); + // 开通记账本 + aliAqfV2Service.fundAccountbookCreate(subjectEntity.getId()); + break; + case "TEMP": + subjectEntity.setSignState((int) TransferSubject.SIGN_STATE_ON_HOLD); + transferSubjectService.updateById(subjectEntity); + break; + case "STOP": + subjectEntity.setSignState((int) TransferSubject.SIGN_STATE_ON_PAUSE); + transferSubjectService.updateById(subjectEntity); + break; + default: + subjectEntity.setSignState((int) TransferSubject.SIGN_STATE_UNKNOWN); + transferSubjectService.updateById(subjectEntity); + break; + } + } catch (Exception e) { + log.error("安全发签约回调异常", e); + transferSubjectService.updateById(subjectEntity); + } + } + + @Override + public Object retOk(JSONObject bizContent) { + return "SUCCESS"; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfKit.java new file mode 100644 index 0000000..2bfee51 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfKit.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.aliaqf; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.alipay.api.internal.util.AlipaySignature; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +/** + * 安全发的一些通用请求,签名等 + * + * @author deng + * @since 2024/5/9 + */ +@Slf4j +public class AliaqfKit { + + // alipay.fund.trans.uni.transfer 涉及的状态:SUCCESS、FAIL、DEALING、REFUND + public static final String ORDER_SUCCESS = "SUCCESS"; + /** 处理中 */ + public static final String ORDER_DEALING = "DEALING"; + /** 退票 */ + public static final String ORDER_REFUND = "REFUND"; + /** 失败 */ + public static final String ORDER_FAIL = "FAIL"; + + public static boolean checkSign(JSONObject reqParamJSON, AliaqfIsvParams isvParams) { + try { + TypeReference> mapTypeReference = new TypeReference>() { + }; + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + return AlipaySignature.rsaCertCheckV1(reqParamJSON.toJavaObject(mapTypeReference), channelCertConfigKitBean.getCertFilePath(isvParams.getAlipayPublicCert()), + AlipayConfig.CHARSET, "RSA2"); + } catch (Exception e) { + log.info("验签失败", e); + } + + return false; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfTransferService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfTransferService.java new file mode 100644 index 0000000..8d7982f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/AliaqfTransferService.java @@ -0,0 +1,251 @@ +package com.jeequan.jeepay.thirdparty.channel.aliaqf; + +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayClient; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayFundTransCommonQueryModel; +import com.alipay.api.domain.AlipayFundTransUniTransferModel; +import com.alipay.api.domain.BankcardExtInfo; +import com.alipay.api.domain.Participant; +import com.alipay.api.request.AlipayFundTransCommonQueryRequest; +import com.alipay.api.request.AlipayFundTransUniTransferRequest; +import com.alipay.api.response.AlipayFundAccountbookQueryResponse; +import com.alipay.api.response.AlipayFundTransCommonQueryResponse; +import com.alipay.api.response.AlipayFundTransUniTransferResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.AccountOperate; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferWallet; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.AccountInfoService; +import com.jeequan.jeepay.service.impl.TransferInterfaceConfigService; +import com.jeequan.jeepay.service.impl.TransferSubjectService; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferService; +import com.jeequan.jeepay.thirdparty.channel.alipay.AliAqfV2Service; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +/** + * TODO + * + * @author deng + * @since 2024/5/11 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AliaqfTransferService extends AbstractTransferService { + private final AccountInfoService accountInfoService; + private final TransferSubjectService transferSubjectService; + private final TransferInterfaceConfigService interfaceConfigService; + private final AliAqfV2Service aliAqfV2Service; + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIAQF; + } + + @Override + public boolean isSupport(String entryType) { + return TransferBasicInfo.ENTRY_TYPE_BANK.equals(entryType) || TransferBasicInfo.ENTRY_TYPE_ZFB.equals(entryType); + } + + public void rollBackServiceCharge(TransferOrder transferOrder) { + // 预扣手续费回退 + TransferSubjectEntity transferSubject = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + String infoId; + if (transferSubject.getInfoType().equals(CS.SYS_ROLE_TYPE.MCH)) { + infoId = transferSubject.getMchNo(); + } else { + infoId = transferSubject.getAgentNo(); + } + AccountInfo accountInfo = accountInfoService.getAccountInfo(infoId, AccountInfo.Type.SERVICE_CHARGE.getType()); + + // 预扣手续费 + AccountOperate accountOperate = new AccountOperate(accountInfo.getAccountNo(), transferOrder.getAmount(), + AccountFundInfo.ChangeType.TRANSFER.getValue(), AccountFundInfo.ChangeMethod.DF.getValue(), + transferOrder.getTransferId(), "代付失败手续费回退"); + accountOperate.setFinalAmt(-transferOrder.getMchOrderFeeAmount()); + accountOperate.setIsUpdateAccount(true); + accountInfoService.upAccount(accountOperate); + + } + + @Override + public ChannelRetMsg transfer(TransferOrderRQ bizRQ, TransferOrder transferOrder) throws Exception { + log.info("进入了支付宝直付通代发!"); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(transferOrder.getIsvNo()); + TransferSubjectEntity ersubjectEntity = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + TransferSubjectEntity eesubjectEntity = transferSubjectService.getById(transferOrder.getTransferSubjectIdJs()); + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); + + model.setOutBizNo(transferOrder.getTransferId()); + model.setTransAmount(AmountUtil.convertCent2Dollar(transferOrder.getAmount())); + model.setProductCode("SINGLE_TRANSFER_NO_PWD"); + model.setBizScene("ENTRUST_TRANSFER"); + model.setOrderTitle(StringUtils.isNotEmpty(transferOrder.getTransferDesc()) ? transferOrder.getTransferDesc() : "支付宝代发到户!"); + //付款方信息 + Participant participanter = new Participant(); + participanter.setIdentity(ersubjectEntity.getTransChannelMchNo()); + participanter.setIdentityType("ACCOUNT_BOOK_ID"); + JSONObject erparm = new JSONObject(); + erparm.put("agreement_no", ersubjectEntity.getTransChannelSignNo()); + participanter.setExtInfo(erparm.toJSONString()); + model.setPayerInfo(participanter); + //收款方信息 + Participant participantee = new Participant(); + participantee.setIdentity(eesubjectEntity.getAccount()); + if (TransferOrderEntity.ENTRY_ALIPAY_CASH.equals(transferOrder.getEntryType())){ + participantee.setIdentityType("ALIPAY_LOGON_ID"); + participantee.setName(eesubjectEntity.getAccountName()); + }else if (TransferOrderEntity.ENTRY_BANK_CARD.equals(transferOrder.getEntryType())){ + participantee.setIdentityType("BANKCARD_ACCOUNT"); + BankcardExtInfo bankcardExtInfo = new BankcardExtInfo(); + participantee.setName(eesubjectEntity.getAccountName()); + if (eesubjectEntity.getAccountType() == TransferBasicInfo.ACCOUNT_TYPE_COR) { + //对公 + String accountMessage = eesubjectEntity.getAccountMessage(); + if (StringUtils.isNotEmpty(accountMessage)) { + JSONObject jsonObject = JSONObject.parseObject(accountMessage); + bankcardExtInfo.setAccountType("1"); + bankcardExtInfo.setInstName(jsonObject.getString("instName")); + bankcardExtInfo.setInstProvince(jsonObject.getString("instProvince")); + bankcardExtInfo.setInstCity(jsonObject.getString("instCity")); + bankcardExtInfo.setInstBranchName(jsonObject.getString("instBranchName")); + participantee.setBankcardExtInfo(bankcardExtInfo); + transferOrder.setBankName(jsonObject.getString("instName")); + } + } else { + //对私 + bankcardExtInfo.setAccountType("2"); + participantee.setBankcardExtInfo(bankcardExtInfo); + } + } + model.setPayeeInfo(participantee); + request.setBizModel(model); + AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request); + retMsg.setChannelAttach(response.getBody()); + if (response.isSuccess()) { + retMsg.setChannelOrderId(response.getOrderId()); + retMsg.setPlatformOrderNo(response.getPayFundOrderId()); + } else { + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + retMsg.setChannelErrMsg(response.getSubMsg()); + retMsg.setChannelErrCode(response.getSubCode()); + } + } catch (Exception e) { + log.info("代发异常!",e); + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + retMsg.setChannelErrMsg(e.getMessage()); + + rollBackServiceCharge(transferOrder); + } + return retMsg; + } + + @Override + public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) { + log.info("进入了支付宝账单查询"); + + TransferSubjectEntity transferSubjectFq = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(transferSubjectFq.getIsvNo()); + AlipayFundTransCommonQueryResponse response; + if ( transferSubjectFq.getTransChannelSignNo() == null || transferSubjectFq.getTransChannelMchNo() == null) { + throw new BizException("当前付款人签约或开通记账本!"); + } + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.UNKNOWN); + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); + model.setProductCode(TransferOrder.ENTRY_BANK_CARD.equals(transferOrder.getEntryType()) ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD"); + model.setBizScene("DIRECT_TRANSFER"); + model.setOutBizNo(transferOrder.getTransferId()); + request.setBizModel(model); + + channelRetMsg.setChannelOrderId(transferOrder.getChannelOrderNo()); + response = alipayClient.certificateExecute(request); + channelRetMsg.setChannelOriginResponse(response.getBody()); + channelRetMsg.setResponseEntity(ResponseEntity.ok("SUCCESS")); + + if (response.isSuccess()) { + log.info("安全发账单查询成功:" + response.getBody()); + } else { + log.error("安全发账单查询失败!" + response.getSubMsg()); + return channelRetMsg; + } + + String status = response.getStatus(); + if (AliaqfKit.ORDER_SUCCESS.equals(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setChannelOrderId(response.getOrderId()); + channelRetMsg.setPlatformOrderNo(response.getPayFundOrderId()); + } else if (AliaqfKit.ORDER_FAIL.equals(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + rollBackServiceCharge(transferOrder); + } else if (AliaqfKit.ORDER_DEALING.equals(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + + return channelRetMsg; + } catch (Exception e) { + log.info("支付宝安全发查询订单状态异常, {}", transferOrder.getTransferId(), e); + } + + return channelRetMsg; + } + + @Override + public MutablePair queryBalanceAmount(TransferWallet transferWallet) { + AlipayFundAccountbookQueryResponse queryResultData = aliAqfV2Service.fundAccountbookQuery(transferWallet.getTransApplyId(), transferWallet.getWalletApplyId()); + + String availableAmount = queryResultData.getAvailableAmount(); + + return new MutablePair<>(transferWallet.getTransApplyId(), AmountUtil.convertDollar2CentLong(availableAmount)); + + } + + public CertAlipayRequest getCertAliPayRequest(String isvNo) { + TransferInterfaceConfigEntity transferInterfaceConfigEntity = interfaceConfigService.getTransferConfig(CS.IF_CODE.ALIAQF, isvNo, CS.SYS_ROLE_TYPE.ISV); + Assert.notNull(transferInterfaceConfigEntity, "所选渠道配置不存在"); + + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + AliaqfIsvParams isvParams = JSONObject.parseObject(transferInterfaceConfigEntity.getTransIfParams(), AliaqfIsvParams.class); + // 支付宝网关 + certAlipayRequest.setServerUrl(AlipayConfig.PROD_SERVER_URL); + certAlipayRequest.setAppId(isvParams.getAppId()); + certAlipayRequest.setPrivateKey(isvParams.getPrivateKey()); + certAlipayRequest.setCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAppPublicCert())); + certAlipayRequest.setAlipayPublicCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAlipayPublicCert())); + certAlipayRequest.setRootCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAlipayRootCert())); + certAlipayRequest.setSignType("RSA2"); + certAlipayRequest.setFormat("json"); + certAlipayRequest.setCharset("UTF-8"); + + return certAlipayRequest; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/model/AliAqfTransferBasicInfo.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/model/AliAqfTransferBasicInfo.java new file mode 100644 index 0000000..50fb3e0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/aliaqf/model/AliAqfTransferBasicInfo.java @@ -0,0 +1,12 @@ +package com.jeequan.jeepay.thirdparty.channel.aliaqf.model; + +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; + +/** + * TODO + * + * @author deng + * @since 2024/5/8 + */ +public class AliAqfTransferBasicInfo extends TransferBasicInfo { +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliAqfV2Service.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliAqfV2Service.java new file mode 100644 index 0000000..75356b1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliAqfV2Service.java @@ -0,0 +1,778 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.CertAlipayRequest; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.diagnosis.DiagnosisUtils; +import com.alipay.api.domain.*; +import com.alipay.api.request.*; +import com.alipay.api.response.*; +import com.jeequan.jeepay.converter.TransferConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.aliaqfbiz.IAliAqfV2ApiService; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Service +@Slf4j +public class AliAqfV2Service implements IAliAqfV2ApiService { + + @Autowired + private SysConfigService sysConfigService; + + @Autowired + private TransferInterfaceConfigService transferInterfaceConfigService; + + @Autowired + private TransferSubjectService transferSubjectService; + + @Autowired + private TransferOrderService transferOrderService; + + @Autowired + private TransferWalletService transferWalletService; + + @Autowired + private TaskListService taskListService; + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private RateConfigService rateConfigService; + + @Autowired + private TransferConverter transferConverter; + + @Autowired + private AccountInfoService accountInfoService; + + private String getOpenCallbackUrl(String subjectId) { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/transferSubject/notify/aliaqf/" + subjectId; + } + + /** + * 签约 + */ + @Override + public String userAgreementPageSign(String subId) { + log.info("进入了支付宝签约"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + if (subjectEntity.getState() == TransferSubject.STATE_DISABLE) { + throw new BizException("当前付款账户已被停用!"); + } + + Assert.notNull(subjectEntity.getTransApplyId(), "申请单号不能为空"); + + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest(); + AlipayUserAgreementPageSignModel model = new AlipayUserAgreementPageSignModel(); + model.setPersonalProductCode("FUND_SAFT_SIGN_WITHHOLDING_P"); + AccessParams accessParams = new AccessParams(); + accessParams.setChannel("QRCODE"); + model.setAccessParams(accessParams); + model.setProductCode("FUND_SAFT_SIGN_WITHHOLDING"); + model.setSignScene("INDUSTRY|SATF_ACC"); + //唯一标识,新建收款账户时生成, + model.setExternalAgreementNo(subjectEntity.getTransApplyId()); + model.setThirdPartyType("PARTNER"); + request.setBizModel(model); + + String openCallbackUrl = getOpenCallbackUrl(subjectEntity.getTransApplyId()); + request.setNotifyUrl(openCallbackUrl); + log.info("安全发签约回调地址:" + openCallbackUrl); + log.info("请求报文:{}", JSONObject.toJSONString(request)); + AlipayUserAgreementPageSignResponse response = alipayClient.pageExecute(request, "get"); + + String pageRedirectionData = response.getBody(); + + if (response.isSuccess()) { + log.info("安全发签约返回:" + response.getBody()); + //设置为签约中 + subjectEntity.setSignState((int) TransferSubject.SIGN_STATE_AUDITING); + subjectEntity.setChannelVar1(pageRedirectionData); + transferSubjectService.updateById(subjectEntity); + + return pageRedirectionData; + } else { + log.info("安全发签约发起请求失败"); + String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response); + + if (ObjUtil.isEmpty(diagnosisUrl)) { + throw new BizException(response.getSubMsg()); + } + + return diagnosisUrl; + } + + } catch (AlipayApiException e) { + log.error("安全发签约请求异常!"); + throw new BizException(e.getErrMsg()); + } + } + + /** + * 支付宝个人代扣协议查询接口 + * + * @param + * @return + */ + @Override + public JSONObject userAgreementQuery(String subId) { + log.info("进入了支付宝个人代扣协议查询接口"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + JSONObject resut = new JSONObject(); + if (certAlipayRequest == null || subjectEntity.getTransApplyId() == null) { + throw new BizException("未获取到当前用户相关信息!"); + } + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayUserAgreementQueryRequest request = new AlipayUserAgreementQueryRequest(); + + AlipayUserAgreementQueryModel model = new AlipayUserAgreementQueryModel(); + model.setPersonalProductCode("FUND_SAFT_SIGN_WITHHOLDING_P"); + model.setSignScene("INDUSTRY|SATF_ACC"); + //签约时传入值 + model.setExternalAgreementNo(subjectEntity.getTransApplyId()); + model.setThirdPartyType("PARTNER"); + request.setBizModel(model); + AlipayUserAgreementQueryResponse response = alipayClient.certificateExecute(request); + resut = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_user_agreement_query_response"); + } catch (Exception e) { + log.error("支付宝个人代扣协议查询异常!",e); + throw new BizException("支付宝个人代扣协议查询异常!"); + } + return resut; + } + + /** + * 解约 + * + * @param + * @return + */ + @Override + public JSONObject userAgreementUnsign(String subId) { + log.info("进入了支付宝个人代扣协议解约接口"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + JSONObject resut = new JSONObject(); + if (certAlipayRequest == null || subjectEntity.getTransApplyId() == null) { + throw new BizException("未获取到当前用户相关信息!"); + } + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayUserAgreementUnsignRequest request = new AlipayUserAgreementUnsignRequest(); + + AlipayUserAgreementUnsignModel model = new AlipayUserAgreementUnsignModel(); + model.setPersonalProductCode("FUND_SAFT_SIGN_WITHHOLDING_P"); + model.setSignScene("INDUSTRY|SATF_ACC"); + //签约时传入值 + model.setExternalAgreementNo(subjectEntity.getTransApplyId()); + //注意:仅异步解约需传入,其余情况无需传递本参数。 + // 解约确认: confirm + //解约作废: invalid + model.setOperateType("confirm"); + request.setBizModel(model); + //request.setNotifyUrl(sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/anf/reqUnsign"); + //log.info("安全发解约回调地址:" + sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/anf/reqNotify"); + AlipayUserAgreementUnsignResponse response = alipayClient.certificateExecute(request); + log.info("支付宝个人代扣协议解约返回参数:" + response.getBody()); + if (response.isSuccess()) { + //直接就是已解约,异步返回暂时不处理 + subjectEntity.setSignState((int)TransferSubject.STATE_ENABLE_REVIEW); + transferSubjectService.updateById(subjectEntity); + } else { + log.info("支付宝个人代扣协议解约失败:" + response.getSubMsg()); + } + resut = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_user_agreement_unsign_response"); + subjectEntity.setChannelVar1(response.getBody()); + } catch (Exception e) { + log.error("支付宝个人代扣协议解约异常!",e); + throw new BizException("支付宝个人代扣协议解约异常!"); + } + return resut; + } + + /** + * 资金记账本开通 + * + * @return + */ + @Override + public void fundAccountbookCreate(String subId) { + + log.info("进入资金记账本开通方法!"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + AliaqfIsvParams isvParams = ((AliaqfIsvParams) configContextQueryService.queryTransferIsvParams(subjectEntity.getIsvNo(), CS.IF_CODE.ALIAQF)); + + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + JSONObject result = new JSONObject(); + TransferSubjectEntity transferSubject = transferSubjectService.getById(subId); + + TransferWalletEntity transferWalletEntity = new TransferWalletEntity(); + AlipayFundAccountbookCreateResponse response; + String merchantUserId = UUID.randomUUID().toString().replace("-", ""); + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundAccountbookCreateRequest request = new AlipayFundAccountbookCreateRequest(); + AlipayFundAccountbookCreateModel model = new AlipayFundAccountbookCreateModel(); + //外部商户系统会员的唯一标识,自定义传入 + model.setMerchantUserId(merchantUserId); + model.setMerchantUserType("BUSINESS_ORGANIZATION"); + model.setSceneCode("SATF_FUND_BOOK"); + //扩展信息: 支付宝协议号必传、企业营业执照认证号(cert_no)可不传。 + //注意:ext_info字段本质上是String类型,所以传递的是转义后的json字符串。 + //agreement_no 签约时回调返回的参数值 + JSONObject param = new JSONObject(); + param.put("agreement_no", transferSubject.getTransChannelSignNo()); + model.setExtInfo(param.toJSONString()); + request.setBizModel(model); + response = alipayClient.certificateExecute(request); + //处理记账本返回信息 + log.info("支付宝安全发记账本开通请求返回参数, {}", response.getBody()); + String responseBody = response.getBody(); + if (response.isSuccess()) { + JSONObject jsonObject = JSONObject.parseObject(responseBody); + ExtCardInfo extCardInfo = response.getExtCardInfo(); + transferSubject.setTransChannelMchNo(response.getAccountBookId()); + //记账本信息 + transferWalletEntity.setTransApplyId(transferSubject.getTransApplyId()); + transferWalletEntity.setTransChannelMchNo(response.getAccountBookId()); + transferWalletEntity.setTransIfCode(transferSubject.getTransIfCode()); + transferWalletEntity.setWalletApplyId(model.getMerchantUserId()); + transferWalletEntity.setExtResponse(jsonObject.toJSONString()); + transferWalletEntity.setIsvNo(transferSubject.getIsvNo()); + transferWalletEntity.setMchNo(transferSubject.getMchNo()); + transferWalletEntity.setSubjectName(transferSubject.getSubjectName()); + transferWalletEntity.setTransIfCode(CS.IF_CODE.ALIAQF); + + transferWalletEntity.setWxMonthMax(0L); + transferWalletEntity.setWxDayMax(0L); + transferWalletEntity.setWxPriOnceMax(0L); + transferWalletEntity.setWxCorOnceMax(0L); + transferWalletEntity.setBankCardCorOnceMax(Long.parseLong(isvParams.getSubBankCardCorOnceMax())); + transferWalletEntity.setBankCardPriOnceMax(Long.parseLong(isvParams.getSubBankCardPriOnceMax())); + transferWalletEntity.setBankCardMonthMax(Long.parseLong(isvParams.getSubBankCardMonthMax())); + transferWalletEntity.setBankCardDayMax(Long.parseLong(isvParams.getSubBankCardDayMax())); + transferWalletEntity.setZfbCorOnceMax(Long.parseLong(isvParams.getSubZfbCorOnceMax())); + transferWalletEntity.setZfbPriOnceMax(Long.parseLong(isvParams.getSubZfbPriOnceMax())); + transferWalletEntity.setZfbMonthMax(Long.parseLong(isvParams.getSubZfbMonthMax())); + transferWalletEntity.setZfbDayMax(Long.parseLong(isvParams.getSubZfbDayMax())); + + if (extCardInfo != null) { + transferWalletEntity.setExtCardInfo(JSONObject.toJSONString(response.getExtCardInfo())); + if ("A".equals(extCardInfo.getStatus())) { + transferWalletEntity.setCardStatus(TransferWalletEntity.CARD_STATUS_NORMAL); + } else { + transferWalletEntity.setCardStatus(TransferWalletEntity.CARD_STATUS_OTHER); + } + } + transferWalletService.save(transferWalletEntity); + } else { + log.info("资金记账本开通失败, {}", response.getSubMsg()); + } + + } catch (Exception e) { + log.info("资金记账本开通异常", e); + } + transferSubjectService.updateById(transferSubject); + } + + /** + * 资金记账本的信息查询 + * + * @return + */ + @Override + public AlipayFundAccountbookQueryResponse fundAccountbookQuery(String subId, String walletApplyId) { + log.info("进入了支付宝资金记账本的信息查询"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + AlipayFundAccountbookQueryResponse response; + if (certAlipayRequest == null || subjectEntity.getTransChannelSignNo() == null + || subjectEntity.getTransChannelMchNo() == null) { + throw new BizException("当前用户暂未签约或配置!"); + } + + try { + TransferWalletEntity walletServiceOne = transferWalletService.getByApplyId(subjectEntity.getTransApplyId(), walletApplyId); + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundAccountbookQueryRequest request = new AlipayFundAccountbookQueryRequest(); + AlipayFundAccountbookQueryModel model = new AlipayFundAccountbookQueryModel(); + //资金记账本id,开通时的返回值 + model.setAccountBookId(subjectEntity.getTransChannelMchNo()); + //商户会员的唯一标识 开通时自定义传入值 + model.setMerchantUserId(walletServiceOne.getWalletApplyId()); + model.setSceneCode("SATF_FUND_BOOK"); + //扩展信息: 支付宝协议号必传 + //注意:ext_info字段本质上是String类型,所以传递的是转义后的json字符串。 + //agreement_no 签约时回调返回的参数值 + JSONObject parm = new JSONObject(); + parm.put("agreement_no", subjectEntity.getTransChannelSignNo()); + model.setExtInfo(parm.toJSONString()); + request.setBizModel(model); + + response = alipayClient.certificateExecute(request); + if (response.isSuccess()) { + String responseBody = response.getBody(); + JSONObject jsonObject = JSONObject.parseObject(responseBody); + JSONObject accountbook = jsonObject.getJSONObject("alipay_fund_accountbook_query_response"); + walletServiceOne.setAccountBookBalance(AmountUtil.convertDollar2CentLong(accountbook.getString("available_amount"))); + JSONObject extCardInfo = accountbook.getJSONObject("ext_card_info"); + if (extCardInfo != null) { + walletServiceOne.setExtCardInfo(extCardInfo.toJSONString()); + if ("A".equals(extCardInfo.getString("status"))) { + walletServiceOne.setCardStatus(1); + } else { + walletServiceOne.setCardStatus(2); + } + } + transferWalletService.updateById(walletServiceOne); + } else { + log.error("资金记账本的信息查询失败!" + response.getSubMsg()); + } + } catch (Exception e) { + log.error("资金记账本的信息查询异常!",e); + throw new BizException("资金记账本的信息查询异常!"); + } + + return response; + } + + /** + * 资金专款拨入(商户自身给记账本充值) + */ + @Override + public String transPage(String subId, String transAmount ,String transferDesc) { + log.info("进入了支付宝资金专款拨入(商户自身给记账本充值)"); + TransferSubjectEntity subjectEntity = getSubjectOne(subId); + String resultUrl = null; + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(subjectEntity.getIsvNo()); + Assert.notNull(subjectEntity, "付款账户不存在"); + + //transferOrderService + TransferOrderEntity transferOrder = new TransferOrderEntity(); + if (subjectEntity.getState() == TransferSubject.STATE_DISABLE) { + throw new BizException("当前付款账户已被停用"); + } + + //获取当前时间1小时后的时间作为过期时间 + String formattedDateTime = LocalDateTime.now().plusHours(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + if (subjectEntity.getTransChannelMchNo() != null + && subjectEntity.getTransChannelSignNo() != null) { + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundTransPagePayRequest request = new AlipayFundTransPagePayRequest(); + AlipayFundTransPagePayModel model = new AlipayFundTransPagePayModel(); + //商户端的唯一订单号,对于同一笔转账请求,商户需保证该订单号唯一。 + model.setOutBizNo("AQF_ZZ_" + SeqKit.genTransOrderId()); + log.info("资金专款拨入outBizNo=====================" + model.getOutBizNo()); + //拨入总金额,单位为元,精确到小数点后两位,取值范围[0.01,9999999999999.99] + model.setTransAmount(transAmount); + // + model.setProductCode("FUND_ACCOUNT_BOOK"); + // + model.setBizScene("SATF_DEPOSIT"); + //充值订单过期时间,默认会失败 + model.setTimeExpire(formattedDateTime); + //收款方信息 + Participant payeeInfo = new Participant(); + //记账本 id + payeeInfo.setIdentity(subjectEntity.getTransChannelMchNo()); + payeeInfo.setIdentityType("ACCOUNT_BOOK_ID"); + //传入记账本id与场景码,不传会校验失败导致充值失败。协议字段必传。 + JSONObject parm = new JSONObject(); + parm.put("agreement_no", subjectEntity.getTransChannelSignNo()); + payeeInfo.setExtInfo(parm.toJSONString()); + model.setPayeeInfo(payeeInfo); + + request.setBizModel(model); + + AlipayFundTransPagePayResponse response = alipayClient.pageExecute(request, "GET"); + if (response.isSuccess()) { + log.info("资金专项拨入结果:" + response.getBody()); + resultUrl = response.getBody(); + //转账中,回调后改变状态 + transferOrder.setState(TransferOrderEntity.STATE_ING); + } else { + log.error("资金专项拨入失败!" + response.getSubMsg()); + resultUrl = response.getSubMsg(); + //转账失败 + transferOrder.setState(TransferOrderEntity.STATE_FAIL); + transferOrder.setErrCode(response.getSubCode()); + transferOrder.setErrMsg(response.getSubMsg()); + } + //将订单信息入库 + // TODO: 2024/4/29 先做简单入库 后续完善 + transferOrder.setAmount(AmountUtil.convertDollar2CentLong(transAmount)); + transferOrder.setTransferId(model.getOutBizNo()); + transferOrder.setMchOrderNo(model.getOutBizNo()); + transferOrder.setTransferType(TransferOrderEntity.TRANSFER_TYPE_ZZ); + transferOrder.setTransferSubjectIdFq(subjectEntity.getId()); + transferOrder.setTransferSubjectIdJs(subjectEntity.getId()); + transferOrder.setMchNo(subjectEntity.getMchNo()); + transferOrder.setMchExtNo(StringUtils.isNotEmpty(subjectEntity.getMchApplyId())?subjectEntity.getMchApplyId():null); + transferOrder.setAgentNo(subjectEntity.getAgentNo()); + transferOrder.setAccountNo(subjectEntity.getAccount()); + transferOrder.setAccountName(subjectEntity.getAccountName()); + transferOrder.setTransferDesc(StringUtils.isNotEmpty(transferDesc)?transferDesc:null); + transferOrderService.save(transferOrder); + } catch (Exception e) { + log.error("资金专项拨入异常!",e); + throw new BizException("资金专项拨入异常!"); + } + } + + return resultUrl; + } + + /** + * 基于记账本代发 + */ + @Override + public ChannelRetMsg transUniTransfer(TransferOrder transferOrder) { + log.info("进入了支付宝代发!"); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(transferOrder.getIsvNo()); + TransferSubjectEntity ersubjectEntity = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + TransferSubjectEntity eesubjectEntity = transferSubjectService.getById(transferOrder.getTransferSubjectIdJs()); + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); + + model.setOutBizNo(transferOrder.getTransferId()); + model.setTransAmount(AmountUtil.convertCent2Dollar(transferOrder.getAmount())); + model.setProductCode("SINGLE_TRANSFER_NO_PWD"); + model.setBizScene("ENTRUST_TRANSFER"); + model.setOrderTitle(StringUtils.isNotEmpty(transferOrder.getTransferDesc()) ? transferOrder.getTransferDesc() : "支付宝代发到户!"); + //付款方信息 + Participant participanter = new Participant(); + participanter.setIdentity(ersubjectEntity.getTransChannelMchNo()); + participanter.setIdentityType("ACCOUNT_BOOK_ID"); + JSONObject erparm = new JSONObject(); + erparm.put("agreement_no", ersubjectEntity.getTransChannelSignNo()); + participanter.setExtInfo(erparm.toJSONString()); + model.setPayerInfo(participanter); + //收款方信息 + Participant participantee = new Participant(); + participantee.setIdentity(eesubjectEntity.getAccount()); + if (TransferOrderEntity.ENTRY_ALIPAY_CASH.equals(transferOrder.getEntryType())){ + participantee.setIdentityType("ALIPAY_LOGON_ID"); + participantee.setName(eesubjectEntity.getAccountName()); + }else if (TransferOrderEntity.ENTRY_BANK_CARD.equals(transferOrder.getEntryType())){ + participantee.setIdentityType("BANKCARD_ACCOUNT"); + BankcardExtInfo bankcardExtInfo = new BankcardExtInfo(); + participantee.setName(eesubjectEntity.getAccountName()); + if (eesubjectEntity.getAccountType() == TransferBasicInfo.ACCOUNT_TYPE_COR) { + //对公 + String accountMessage = eesubjectEntity.getAccountMessage(); + if (StringUtils.isNotEmpty(accountMessage)) { + JSONObject jsonObject = JSONObject.parseObject(accountMessage); + bankcardExtInfo.setAccountType("1"); + bankcardExtInfo.setInstName(jsonObject.getString("instName")); + bankcardExtInfo.setInstProvince(jsonObject.getString("instProvince")); + bankcardExtInfo.setInstCity(jsonObject.getString("instCity")); + bankcardExtInfo.setInstBranchName(jsonObject.getString("instBranchName")); + participantee.setBankcardExtInfo(bankcardExtInfo); + transferOrder.setBankName(jsonObject.getString("instName")); + } + } else { + //对私 + bankcardExtInfo.setAccountType("2"); + participantee.setBankcardExtInfo(bankcardExtInfo); + } + } + model.setPayeeInfo(participantee); + request.setBizModel(model); + AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request); + retMsg.setChannelAttach(response.getBody()); + if (response.isSuccess()) { + retMsg.setChannelOrderId(response.getOrderId()); + retMsg.setPlatformOrderNo(response.getPayFundOrderId()); + } else { + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + retMsg.setChannelErrMsg(response.getSubMsg()); + retMsg.setChannelErrCode(response.getSubCode()); + } + } catch (Exception e) { + log.info("代发异常!",e); + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + retMsg.setChannelErrMsg(e.getMessage()); + } + return retMsg; + } + /** + * 账单查询 + */ + + @Override + public JSONObject bizfundagentQuery(String subId, String startTime, String endTime, String pageNo, String pageSize) { + log.info("进入了支付宝账单查询"); + TransferSubjectEntity ersubjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(ersubjectEntity.getIsvNo()); + JSONObject resut = new JSONObject(); + AlipayDataBillBizfundagentQueryResponse response = new AlipayDataBillBizfundagentQueryResponse(); + if ( ersubjectEntity.getTransChannelSignNo() == null || ersubjectEntity.getTransChannelMchNo() == null) { + throw new BizException("当前付款人签约或开通记账本!"); + } + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayDataBillBizfundagentQueryRequest request = new AlipayDataBillBizfundagentQueryRequest(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("start_time", startTime); + jsonObject.put("end_time", endTime); + jsonObject.put("page_no", StringUtils.isEmpty(pageNo) ? "1" : pageNo); + jsonObject.put("page_size", StringUtils.isEmpty(pageSize) ? "2000" : pageSize); + jsonObject.put("agreement_no", ersubjectEntity.getTransChannelSignNo()); + jsonObject.put("account_book_id", ersubjectEntity.getTransChannelMchNo()); + request.setBizContent(jsonObject.toJSONString()); + + response = alipayClient.certificateExecute(request); + if (response.isSuccess()) { + log.info("安全发账单查询成功:" + response.getBody()); + } else { + log.error("安全发账单查询失败!" + response.getSubMsg()); + } + resut = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_data_bill_bizfundagent_query_response"); + } catch (Exception e) { + resut.put("code", "99999"); + resut.put("subMsg", "安全发账单查询异常!!"); + log.error("安全发账单查询异常!",e); + } + return resut; + } + + /** + * 申请电子回单 + */ + + @Override + public JSONObject applicationForm(String subId, String transferId) { + log.info("进入了支付宝申请电子回单"); + TransferSubjectEntity ersubjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(ersubjectEntity.getIsvNo()); + TransferOrderEntity transferOrder = transferOrderService.getById(transferId); + JSONObject resut = new JSONObject(); + AlipayDataBillEreceiptagentApplyResponse response; + if (ersubjectEntity.getTransChannelSignNo() == null || transferOrder == null || transferOrder.getFlowNo() == null) { + throw new BizException("当前付款人不符合申请条件!"); + } + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayDataBillEreceiptagentApplyRequest request = new AlipayDataBillEreceiptagentApplyRequest(); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("type", "FUND_DETAIL"); + jsonObject.put("key", transferOrder.getFlowNo()); + jsonObject.put("agreement_no", ersubjectEntity.getTransChannelSignNo()); + request.setBizContent(jsonObject.toJSONString()); + + response = alipayClient.certificateExecute(request); + if (response.isSuccess()) { + log.info("申请电子回单:" + response.getBody()); + transferOrder.setApplicationFormState(1); + transferOrder.setApplicationFileId(response.getFileId()); + transferOrderService.updateById(transferOrder); + } else { + log.error("申请电子回单失败!" + response.getSubMsg()); + } + resut = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_data_bill_ereceiptagent_apply_response"); + } catch (Exception e) { + resut.put("code", "99999"); + resut.put("subMsg", "申请电子回单异常!!"); + log.error("申请电子回单异常!",e); + } + return resut; + } + + /** + * 回单申请状态和下载地址 + */ + + @Override + public JSONObject applicationFormDownload(String subId, String transferId) { + log.info("进入了支付宝回单申请状态和下载地址"); + TransferSubjectEntity ersubjectEntity = getSubjectOne(subId); + CertAlipayRequest certAlipayRequest = getCertAliPayRequest(ersubjectEntity.getIsvNo()); + TransferOrderEntity transferOrder = transferOrderService.getById(transferId); + JSONObject resut = new JSONObject(); + + AlipayDataBillAccountbookereceiptQueryResponse response; + if (ersubjectEntity.getTransChannelSignNo() == null || transferOrder == null || transferOrder.getApplicationFileId() == null) { + throw new BizException("当前付款人不符合申请条件!"); + } + + try { + AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest); + AlipayDataBillAccountbookereceiptQueryRequest request = new AlipayDataBillAccountbookereceiptQueryRequest(); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("file_id", transferOrder.getApplicationFileId()); + jsonObject.put("agreement_no", ersubjectEntity.getTransChannelSignNo()); + request.setBizContent(jsonObject.toJSONString()); + response = alipayClient.certificateExecute(request); + if (response.isSuccess()) { + log.info("回单申请状态和下载地址返回:" + response.getBody()); + } else { + log.error("回单申请状态和下载地址失败!" + response.getSubMsg()); + } + resut = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_data_bill_accountbookereceipt_query_response"); + } catch (Exception e) { + resut.put("code", "99999"); + resut.put("subMsg", "回单申请状态和下载地址异常!!"); + log.error("回单申请状态和下载地址异常!",e); + } + return resut; + } + + + /** + * 生成待发待结算信息 + * + * @return + */ + public String settlementData(String ersubId, List entityList, String taskId, String entryType, String accountType) { + String resut = "操作成功!"; + TransferSubjectEntity transferSubject = transferSubjectService.getById(ersubId); + if (transferSubject.getState() == TransferSubject.STATE_DISABLE) { + throw new BizException("当前付款账户已停用!"); + } + if (ObjUtil.isEmpty(entityList)) { + throw new BizException("收款人不能为空!"); + } + if (transferSubject.getTransChannelMchNo() == null || transferSubject.getTransChannelSignNo() == null) { + throw new BizException("付款账户暂未签约或开通记账本!"); + } + TaskList task = taskListService.getById(taskId); + //先进行手续费账户余额校验 + long total = 0; + for (TransferOrder transferOrder : entityList) { + long transAmountInCent = AmountUtil.convertDollar2CentLong(transferOrder.getTransAmount()); // 将金额转换为以分为单位 + total += transAmountInCent ;//累加转化后的金额 + } + + String infoId; + if (CS.SYS_ROLE_TYPE.AGENT.equals(transferSubject.getInfoType())) { + infoId = transferSubject.getAgentNo(); + } else { + infoId = transferSubject.getMchNo(); + } + + accountInfoService.checkBalance(infoId, AccountInfo.Type.SERVICE_CHARGE, total); + Map map = new HashMap<>(); + for (TransferOrder item: entityList) { + TransferSubject itemJsInfo = map.get(item.getTransferSubjectIdJs()); + if (itemJsInfo == null) { + itemJsInfo = transferSubjectService.getById(item.getTransferSubjectIdJs()); + map.put(item.getTransferSubjectIdJs(), itemJsInfo); + } + + // ersubId:付款方id eesubId:收款方id + // TODO: 2024/4/30 后续完善参数 + TransferOrderEntity transferOrder = transferConverter.toDbEntity(item); + transferOrder.setTransferId("AQF_ZZ_" + SeqKit.genTransOrderId()); + transferOrder.setMchNo(transferSubject.getMchNo()); + transferOrder.setMchExtNo(transferSubject.getMchApplyId()); + transferOrder.setIsvNo(transferSubject.getIsvNo()); + transferOrder.setAgentNo(transferSubject.getAgentNo()); + transferOrder.setTaskId(taskId); + transferOrder.setTransferSubjectIdFq(ersubId); + transferOrder.setTransferSubjectIdJs(item.getTransferSubjectIdJs()); + transferOrder.setAccountType(accountType); + transferOrder.setTaskId(task.getId()); + transferOrder.setTaskName(task.getTaskName()); + transferOrder.setAccountNo(itemJsInfo.getAccount()); + transferOrder.setAccountName(itemJsInfo.getAccountName()); + transferOrder.setOriginAccountNo(transferSubject.getAccount()); + transferOrder.setOriginAccountName(transferSubject.getAccountName()); + Long transAmount = AmountUtil.convertDollar2CentLong(item.getTransAmount()); + transferOrder.setIfCode(CS.IF_CODE.ALIAQF); + transferOrder.setAmount(transAmount); + transferOrder.setEntryType(entryType); + Map paywayFeeMap = rateConfigService.queryPaywayFeeMap(RateConfig.appendInfoByMchApp(transferSubject.getMchNo()), CS.SYS_ROLE_TYPE.MCH, transferSubject.getTransIfCode(), null, null, transferSubject.getIsvNo(), true); + if(paywayFeeMap == null){ + throw new BizException("转账费率信息异常"); + } + PaywayFee paywayFee = paywayFeeMap.get(transferOrder.getEntryType()); + if(paywayFee == null){ + throw new BizException("未获取到指定的打款方式的费率信息"); + } + MutablePair feeAndSnapshot = paywayFee.calFeeAndSnapshot(transAmount); + transferOrder.setFeeCostType(TransferOrder.COST_TYPE_ACCOUNT); + transferOrder.setMchFeeRate(feeAndSnapshot.left); + transferOrder.setMchOrderFeeAmount(feeAndSnapshot.right); + transferOrder.setTransferDesc(item.getTransferDesc()); + if (StringUtils.isNotEmpty(item.getBatchId())) { + transferOrder.setBatchId(item.getBatchId()); + } + transferOrder.setTransferType(TransferOrderEntity.TRANSFER_TYPE_DF); + transferOrderService.save(transferOrder); + } + return resut; + } + + public CertAlipayRequest getCertAliPayRequest(String isvNo) { + TransferInterfaceConfigEntity transferInterfaceConfigEntity = transferInterfaceConfigService.getTransferConfig(CS.IF_CODE.ALIAQF, isvNo, CS.SYS_ROLE_TYPE.ISV); + Assert.notNull(transferInterfaceConfigEntity, "所选渠道配置不存在"); + + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + AliaqfIsvParams isvParams = JSONObject.parseObject(transferInterfaceConfigEntity.getTransIfParams(), AliaqfIsvParams.class); + // 支付宝网关 + certAlipayRequest.setServerUrl(AlipayConfig.PROD_SERVER_URL); + certAlipayRequest.setAppId(isvParams.getAppId()); + certAlipayRequest.setPrivateKey(isvParams.getPrivateKey()); + certAlipayRequest.setCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAppPublicCert())); + certAlipayRequest.setAlipayPublicCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAlipayPublicCert())); + certAlipayRequest.setRootCertPath(channelCertConfigKitBean.getCertFilePath(isvParams.getAlipayRootCert())); + certAlipayRequest.setSignType("RSA2"); + certAlipayRequest.setFormat("json"); + certAlipayRequest.setCharset("UTF-8"); + + return certAlipayRequest; + } + + /** + * 根据付款人信息id获取详情 + */ + public TransferSubjectEntity getSubjectOne(String subId){ + TransferSubjectEntity transferSubjectEntity = transferSubjectService.getById(subId); + if (transferSubjectEntity != null){ + return transferSubjectEntity; + }else { + throw new BizException("未查询到当前付款人信息!"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliaqfTransferNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliaqfTransferNoticeService.java new file mode 100644 index 0000000..1385f28 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AliaqfTransferNoticeService.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.TransferConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.db.entity.TransferOrderEntity; +import com.jeequan.jeepay.service.impl.TransferOrderService; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +/** + * TODO + * + * @author deng + * @since 2024/5/8 + */ +@Service +@Slf4j +public class AliaqfTransferNoticeService extends AbstractTransferNoticeService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private TransferOrderService transferOrderService; + + @Autowired + private TransferConverter transferConverter; + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIAQF; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + log.info("【支付宝安全发接口回调】, 原始参数为{}", reqParamJSON); + + String input = reqParamJSON.getString("input"); + if (ObjUtil.isEmpty(input)) { + return new MutablePair<>(); + } + + String[] params = input.split("&"); + + JSONObject decryptParam = new JSONObject(); + for (String paramItem : params) { + String[] real = paramItem.split("="); + if (real.length != 2) { + log.info("回调参数格式不正确, {}", paramItem); + return new MutablePair<>(); + } + + try { + decryptParam.put(URLDecoder.decode(real[0], "UTF-8"),URLDecoder.decode(real[1], "UTF-8")); + } catch (UnsupportedEncodingException e) { + log.error("参数解析异常, {}", real[1], e); + } + } + + JSONObject bizContent = decryptParam.getJSONObject("biz_content"); + log.info("【支付宝安全发接口回调】, 解密后业务参数为{}", bizContent); + + String outBizNo = bizContent.getString("out_biz_no"); + return new MutablePair<>(outBizNo, bizContent); + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, TransferOrder transferOrder) { + JSONObject bizContent = ((JSONObject) params); + ChannelRetMsg result = new ChannelRetMsg(); + result.setChannelOrderId(bizContent.getString("order_id")); + result.setPlatformOrderNo(bizContent.getString("pay_fund_order_id")); + result.setChannelOriginResponse(bizContent.toJSONString()); + switch (bizContent.getString("status")){ + case "SUCCESS" : + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case "CLOSED" : + case "FAIL" : + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + result.setChannelErrMsg(bizContent.getString("sub_order_fail_reason")); + break; + default: + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + transferOrder.setState(TransferOrderEntity.STATE_ING); + break; + } + + ResponseEntity ok = ResponseEntity.ok(retOk(null)); + result.setResponseEntity(ok); + + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayBillDownloadService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayBillDownloadService.java new file mode 100644 index 0000000..1ee8262 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayBillDownloadService.java @@ -0,0 +1,174 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.csv.CsvData; +import cn.hutool.core.text.csv.CsvRow; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alipay.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel; +import com.alipay.api.request.AlipayDataDataserviceBillDownloadurlQueryRequest; +import com.alipay.api.response.AlipayDataDataserviceBillDownloadurlQueryResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.CheckBatch; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.bill.ChannelBill; +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 com.jeequan.jeepay.core.model.params.alipay.AlipayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.CheckChannelBill; +import com.jeequan.jeepay.thirdparty.channel.AbstractBillDownloadService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.zip.ZipEntry; + +/* +* 支付宝 对账单下载 +* +* @author zx +* +* @date 2021/6/8 17:20 +*/ +@Slf4j +@Service +public class AlipayBillDownloadService extends AbstractBillDownloadService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public ChannelBillRS convertStandardBill(ChannelBillRQ channelBillRQ, MchAppConfigContext mchAppConfigContext, Date billDate, String ifCode){ + + String logPrefix = "【支付宝对账单下载】"; + + ChannelBillRS channelBillRes = new ChannelBillRS(); + + AlipayDataDataserviceBillDownloadurlQueryRequest req = new AlipayDataDataserviceBillDownloadurlQueryRequest(); + AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel(); + req.setBizModel(model); + + model.setBillDate(DateUtil.formatDate(billDate)); + model.setBillType("trade"); + + String channelMchNo = channelBillRQ.getChannelMchNo(); // 渠道商户号 + + // 特约商户, 放置子商户token + if(mchAppConfigContext.isIsvsubMch()){ + AlipayIsvsubMchParams isvsubMchParams = (AlipayIsvsubMchParams) channelBillRQ.getIsvsubMchParams(); + req.putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } + + // 账单文件流 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + try { + AlipayDataDataserviceBillDownloadurlQueryResponse resp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + log.info("{},返回结果:{}", logPrefix, JSON.toJSONString(resp)); + if (!resp.isSuccess()) { + throw new BizException(resp.getCode() + "[" + resp.getMsg() + "]," + resp.getSubCode() + "[" + resp.getSubMsg() + "]"); + } + + // 下载对账单,写入文件输出流 + HttpUtil.download(resp.getBillDownloadUrl(), byteArrayOutputStream, false); + + // 上传oss + String url = upload2Oss(ifCode, channelMchNo, billDate, ".zip", IoUtil.toStream(byteArrayOutputStream)); + // 生成附带对账文件下载地址的解析成功的批次 + CheckBatch checkBatch = genReleaseSuccessCheckBatch(ifCode, billDate, channelMchNo, url); + // 渠道账单列表 + List channelBillList = new ArrayList<>(); + // 渠道总退款金额 + long channelTotalRefundAmount = 0; + + // 读取对账单 csv文件 + List> mutablePairs = ExcelUtil.readCsvDataByZipInputStream(IoUtil.toStream(byteArrayOutputStream), CharsetUtil.CHARSET_GBK, CharsetUtil.CHARSET_GBK); + + for (MutablePair mutablePair : mutablePairs) { + CsvData data = mutablePair.right; + List rows = data.getRows(); + + // 汇总数据 + if (mutablePair.left.getName().contains("汇总")) { + if (rows.size() > 1) { + List rawList = rows.get(1).getRawList(); + + if (rawList.size() > 10) { + checkBatch.setChannelTotalCount(Integer.valueOf(rawList.get(2).trim())); + checkBatch.setChannelTotalRefundCount(Integer.valueOf(rawList.get(3).trim())); + checkBatch.setChannelTotalAmount(AmountUtil.convertDollar2CentLong(rawList.get(4).trim())); + checkBatch.setChannelTotalFee(AmountUtil.convertDollar2CentLong(rawList.get(9).trim())); + } + } + + // 明细数据 + }else{ + // 遍历行 + for (int i = 1; i < rows.size(); i++) { + CsvRow csvRow = rows.get(i); + // getRawList返回一个List列表,列表的每一项为CSV中的一个单元格 + List rawList = csvRow.getRawList(); + + if (rawList.size() > 22) { + ChannelBill channelBill = new ChannelBill(); + channelBill.setBatchNo(checkBatch.getBatchNo()); + channelBill.setBillDate(billDate); + channelBill.setIfCode(ifCode); + channelBill.setChannelMchNo(channelMchNo); + channelBill.setChannelOrderNo(rawList.get(0).trim()); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(11).trim()))); + channelBill.setChannelFeeAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(22).trim()))); + channelBill.setChannelSuccessAt(DateUtil.parseDateTime(rawList.get(5).trim())); + channelBill.setChannelUser(rawList.get(10).trim()); + + if (StringUtils.equals(rawList.get(2).trim(), "交易")) { + channelBill.setOrderId(rawList.get(1).trim()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_PAY); + channelBill.setChannelState((byte) 2); + }else if (StringUtils.equals(rawList.get(2).trim(), "退款")) { + channelBill.setOrderId(rawList.get(21).trim()); // 平台退款订单号 + channelBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND); + channelBill.setChannelState((byte) 5); + channelBill.setOrgPayOrderId(rawList.get(1).trim()); + + channelTotalRefundAmount += channelBill.getChannelAmount(); + }else { + log.error("支付宝账单类型错误!"); + continue; + } + + channelBillList.add(channelBill); + } + } + } + } + + checkBatch.setChannelTotalRefundAmount(channelTotalRefundAmount); + checkBatch.setChannelTotalAmount(checkBatch.getChannelTotalAmount() + Math.abs(channelTotalRefundAmount)); + + channelBillRes.setCheckBatch(checkBatch); + channelBillRes.setChannelBillList(channelBillList); + + return channelBillRes; + }catch (Exception e) { + log.error("{}, 解析对账文件失败,", logPrefix, e); + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage())); + return channelBillRes; + }finally { + IoUtil.close(byteArrayOutputStream); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayChannelNoticeService.java new file mode 100644 index 0000000..015674a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayChannelNoticeService.java @@ -0,0 +1,128 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.internal.util.AlipaySignature; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/* +* 支付宝 回调接口实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:20 +*/ +@Service +@Slf4j +public class AlipayChannelNoticeService extends AbstractChannelNoticeService { + + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + + JSONObject params = getReqParamJSON(); + String payOrderId = params.getString("out_trade_no"); + return MutablePair.of(payOrderId, params); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + + //配置参数获取 + Byte useCert = null; + String alipaySignType, alipayPublicCert, alipayPublicKey = null; + if(mchAppConfigContext.isIsvsubMch()){ + + // 获取支付参数 + AlipayIsvParams alipayParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + useCert = alipayParams.getUseCert(); + alipaySignType = alipayParams.getSignType(); + alipayPublicCert = alipayParams.getAlipayPublicCert(); + alipayPublicKey = alipayParams.getAlipayPublicKey(); + + }else{ + + // 获取支付参数 + AlipayNormalMchParams alipayParams = (AlipayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + useCert = alipayParams.getUseCert(); + alipaySignType = alipayParams.getSignType(); + alipayPublicCert = alipayParams.getAlipayPublicCert(); + alipayPublicKey = alipayParams.getAlipayPublicKey(); + } + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + + boolean verifyResult; + if(useCert != null && useCert == CS.YES){ //证书方式 + + verifyResult = AlipaySignature.rsaCertCheckV1(jsonParams.toJavaObject(Map.class), getCertFilePath(alipayPublicCert), + AlipayConfig.CHARSET, alipaySignType); + + }else{ + verifyResult = AlipaySignature.rsaCheckV1(jsonParams.toJavaObject(Map.class), alipayPublicKey, AlipayConfig.CHARSET, alipaySignType); + } + + //验签失败 + if(!verifyResult){ + throw ResponseException.buildText("ERROR"); + } + + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("SUCCESS"); + + ChannelRetMsg result = new ChannelRetMsg(); + result.setChannelOrderId(jsonParams.getString("trade_no")); //渠道订单号 + result.setPlatformOrderNo(jsonParams.getString("trade_no")); + result.setPlatformMchOrderNo(payOrder.getPayOrderId()); + result.setChannelUserId(jsonParams.getString("buyer_id")); //支付用户ID + result.setResponseEntity(okResponse); //响应数据 + result.setChannelBizData(jsonParams); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + + if("TRADE_SUCCESS".equals(jsonParams.getString("trade_status"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if("TRADE_CLOSED".equals(jsonParams.getString("trade_status"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + + } + + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayDivisionService.java new file mode 100644 index 0000000..f6179ad --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayDivisionService.java @@ -0,0 +1,214 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSON; +import com.alipay.api.domain.*; +import com.alipay.api.request.AlipayTradeOrderSettleRequest; +import com.alipay.api.request.AlipayTradeRoyaltyRelationBindRequest; +import com.alipay.api.response.AlipayTradeOrderSettleResponse; +import com.alipay.api.response.AlipayTradeRoyaltyRelationBindResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.RegKit; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** +* 分账接口: 支付宝官方 +* +* @author terrfly +* +* @date 2021/8/22 09:05 +*/ +@Slf4j +@Service +public class AlipayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public boolean divisionRefundIsOrderRefundAfterProc() { + return true; // 事后分账回退 + } + + // 分账回退, 默认成功。 + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + return ChannelRetMsg.confirmSuccess(null); + } + + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + + try { + AlipayTradeRoyaltyRelationBindRequest request = new AlipayTradeRoyaltyRelationBindRequest(); + AlipayTradeRoyaltyRelationBindModel model = new AlipayTradeRoyaltyRelationBindModel(); + request.setBizModel(model); + model.setOutRequestNo(SeqKit.genDivisionBatchId()); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + + RoyaltyEntity royaltyEntity = new RoyaltyEntity(); + + royaltyEntity.setType("loginName"); + if(RegKit.isAlipayUserId(mchDivisionReceiver.getAccNo())){ + royaltyEntity.setType("userId"); + } + royaltyEntity.setAccount(mchDivisionReceiver.getAccNo()); + royaltyEntity.setName(mchDivisionReceiver.getAccName()); + royaltyEntity.setMemo(mchDivisionReceiver.getRelationTypeName()); //分账关系描述 + model.setReceiverList(Arrays.asList(royaltyEntity)); + + AlipayTradeRoyaltyRelationBindResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request); + + if(alipayResp.isSuccess()){ + return ChannelRetMsg.confirmSuccess(null); + } + + //异常: + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + return channelRetMsg; + + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("绑定支付宝账号异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + + + try { + + if(recordList.isEmpty()){ // 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。 + return ChannelRetMsg.confirmSuccess(null); + } + + AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest(); + AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel(); + request.setBizModel(model); + + model.setOutRequestNo(recordList.get(0).getBatchOrderId()); //结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。 + model.setTradeNo(recordList.get(0).getPayOrderChannelOrderNo()); //支付宝订单号 + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + + List reqReceiverList = new ArrayList<>(); + + for (int i = 0; i < recordList.size(); i++) { + + PayOrderDivisionRecord record = recordList.get(i); + + if(record.getCalDivisionAmount() <= 0){ //金额为 0 不参与分账处理 + continue; + } + + OpenApiRoyaltyDetailInfoPojo reqReceiver = new OpenApiRoyaltyDetailInfoPojo(); + reqReceiver.setRoyaltyType("transfer"); //分账类型: 普通分账 + + // 出款信息 + // reqReceiver.setTransOutType("loginName"); reqReceiver.setTransOut("xqxemt4735@sandbox.com"); + + // 入款信息 + reqReceiver.setTransIn(record.getAccNo()); //收入方账号 + reqReceiver.setTransInType("loginName"); + if(RegKit.isAlipayUserId(record.getAccNo())){ + reqReceiver.setTransInType("userId"); + } + // 分账金额 + reqReceiver.setAmount(AmountUtil.convertCent2Dollar(record.getCalDivisionAmount())); + reqReceiver.setDesc("[" + payOrder.getPayOrderId() + "]订单分账"); + reqReceiverList.add(reqReceiver); + + } + + if(reqReceiverList.isEmpty()){ // 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。 + return ChannelRetMsg.confirmSuccess(null); + } + + model.setRoyaltyParameters(reqReceiverList); // 分账明细信息 + + // 完结 + SettleExtendParams settleExtendParams = new SettleExtendParams(); + settleExtendParams.setRoyaltyFinish("true"); + model.setExtendParams(settleExtendParams); + + //调起支付宝分账接口 + if(log.isInfoEnabled()){ + log.info("订单:[{}], 支付宝分账请求:{}", payOrder.getPayOrderId(), JSON.toJSONString(model)); + } + AlipayTradeOrderSettleResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request); + log.info("订单:[{}], 支付宝分账响应:{}", payOrder.getPayOrderId(), alipayResp.getBody()); + if(alipayResp.isSuccess()){ + return ChannelRetMsg.confirmSuccess(alipayResp.getTradeNo()); + } + + //异常: + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + return channelRetMsg; + + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("绑定支付宝账号异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayIotDeviceBindService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayIotDeviceBindService.java new file mode 100644 index 0000000..dff9ecc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayIotDeviceBindService.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.AlipayCommerceIotDeviceBindModel; +import com.alipay.api.domain.AlipayCommerceIotDeviceBindQueryModel; +import com.alipay.api.domain.AlipayCommerceIotDeviceUnbindModel; +import com.alipay.api.request.AlipayCommerceIotDeviceBindQueryRequest; +import com.alipay.api.request.AlipayCommerceIotDeviceBindRequest; +import com.alipay.api.request.AlipayCommerceIotDeviceUnbindRequest; +import com.alipay.api.response.AlipayCommerceIotDeviceBindQueryResponse; +import com.alipay.api.response.AlipayCommerceIotDeviceBindResponse; +import com.alipay.api.response.AlipayCommerceIotDeviceUnbindResponse; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayIotDeviceBindService; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* +* 支付宝Iot设备接口 +* +* @author zx +* +* @date 2023/3/8 15:13 +*/ +@Slf4j +@Service +public class AlipayIotDeviceBindService implements IAlipayIotDeviceBindService { + + @Override + public void bind(AlipayIsvParams alipayIsvParams, String mchNo, String alipayMerchantNo, String alipayShopId, String supplierId, JSONObject deviceJSON) { + AlipayCommerceIotDeviceBindRequest request = new AlipayCommerceIotDeviceBindRequest(); + AlipayCommerceIotDeviceBindModel model = new AlipayCommerceIotDeviceBindModel(); + model.setAppType("MINI_APP"); + model.setMiniAppId("RUYI_LITE"); + model.setDeviceIdType("SN"); + model.setDeviceSn(deviceJSON.getString("deviceNo")); + model.setSupplierId(supplierId); // 设备供应商ID: + model.setExternalId(mchNo); // jeepay商户号 + model.setMerchantIdType("direct"); + model.setMerchantId(alipayMerchantNo); + model.setShopId(alipayShopId); + model.setSource(alipayIsvParams.getPid()); // 受理商户的ISV在支付宝的pid + model.setSpiAppId(alipayIsvParams.getAppId()); // 表示ISV在开放平台注册的SPI服务应用的app_id + model.setTerminalBindInfo(deviceJSON.toJSONString()); // 由ISV自定义的扩展字段,在支付宝侧向SPI服务发起请求时透传给ISV + + request.setBizModel(model); + AlipayCommerceIotDeviceBindResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("alipayIot设备绑定响应,deviceNo={},response={}", deviceJSON.getString("deviceNo"), JSONObject.toJSONString(response)); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + } + + @Override + public void unbind(AlipayIsvParams alipayIsvParams, String mchNo, String alipayMerchantNo, String alipayShopId, String supplierId, String deviceSn){ + AlipayCommerceIotDeviceUnbindRequest request = new AlipayCommerceIotDeviceUnbindRequest(); + AlipayCommerceIotDeviceUnbindModel model = new AlipayCommerceIotDeviceUnbindModel(); + model.setAppType("MINI_APP"); + model.setMiniAppId("RUYI_LITE"); + model.setDeviceIdType("SN"); + model.setDeviceSn(deviceSn); + model.setSupplierId(supplierId); + model.setSource(alipayIsvParams.getPid()); + model.setExternalId(mchNo); // jeepay商户号 1678169795992 + model.setMerchantIdType("direct"); + model.setMerchantId(alipayMerchantNo); + model.setShopId(alipayShopId); + + request.setBizModel(model); + AlipayCommerceIotDeviceUnbindResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("alipayIot设备解绑响应,deviceNo:{},response={}", deviceSn, JSONObject.toJSONString(response)); + if ("NOT_BIND".equals(response.getSubCode())) { + return; + } + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + } + + @Override + public JSONObject query(AlipayIsvParams alipayIsvParams, String deviceSn){ + AlipayCommerceIotDeviceBindQueryRequest request = new AlipayCommerceIotDeviceBindQueryRequest(); + AlipayCommerceIotDeviceBindQueryModel model = new AlipayCommerceIotDeviceBindQueryModel(); + model.setAppType("MINI_APP"); + model.setMiniAppId("RUYI_LITE"); + model.setDeviceIdType("SN"); + model.setDeviceSn(deviceSn); + request.setBizModel(model); + + AlipayCommerceIotDeviceBindQueryResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("alipayIot设备查询响应,deviceNo:{},response:{}", deviceSn, JSONObject.toJSONString(response)); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + return (JSONObject) JSONObject.toJSON(response); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayKit.java new file mode 100644 index 0000000..d8c621f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayKit.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import cn.hutool.core.text.CharSequenceUtil; +import com.alipay.api.AlipayObject; +import com.alipay.api.AlipayRequest; +import com.alipay.api.domain.*; +import com.alipay.api.request.*; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.model.AlipayClientWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.apache.commons.lang3.StringUtils; + +/* +* 【支付宝】支付通道工具包 +* +* @author terrfly +* +* @date 2021/6/8 17:19 +*/ +public class AlipayKit { + + /** 放置 isv特殊信息 **/ + public static void putApiIsvInfo(MchAppConfigContext mchAppConfigContext, AlipayRequest req, AlipayObject model){ + + //不是特约商户, 无需放置此值 + if(!mchAppConfigContext.isIsvsubMch()){ + return ; + } + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + + // 获取支付参数 + AlipayIsvParams isvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + AlipayIsvsubMchParams isvsubMchParams = (AlipayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY); + + // 子商户信息 + if(req instanceof AlipayTradePayRequest) { + ((AlipayTradePayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeAppPayRequest) { + ((AlipayTradeAppPayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeCreateRequest) { + ((AlipayTradeCreateRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradePagePayRequest) { + ((AlipayTradePagePayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradePrecreateRequest) { + ((AlipayTradePrecreateRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeWapPayRequest) { + ((AlipayTradeWapPayRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeQueryRequest) { + ((AlipayTradeQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeRefundRequest) { + ((AlipayTradeRefundRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeFastpayRefundQueryRequest) { + ((AlipayTradeFastpayRefundQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayFundTransToaccountTransferRequest) { + ((AlipayFundTransToaccountTransferRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeRoyaltyRelationBindRequest) { + ((AlipayTradeRoyaltyRelationBindRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayTradeOrderSettleRequest) { + ((AlipayTradeOrderSettleRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } else if(req instanceof AlipayDataDataserviceBillDownloadurlQueryRequest) { + ((AlipayDataDataserviceBillDownloadurlQueryRequest)req).putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken()); + } + + // 服务商信息 + ExtendParams extendParams = new ExtendParams(); + extendParams.setSysServiceProviderId(isvParams.getPid()); + + if(model instanceof AlipayTradePayModel) { + ((AlipayTradePayModel)model).setExtendParams(extendParams); + } else if(model instanceof AlipayTradeAppPayModel) { + ((AlipayTradeAppPayModel)model).setExtendParams(extendParams); + } else if(model instanceof AlipayTradeCreateModel) { + ((AlipayTradeCreateModel)model).setExtendParams(extendParams); + } else if(model instanceof AlipayTradePagePayModel) { + ((AlipayTradePagePayModel)model).setExtendParams(extendParams); + } else if(model instanceof AlipayTradePrecreateModel) { + ((AlipayTradePrecreateModel)model).setExtendParams(extendParams); + } else if(model instanceof AlipayTradeWapPayModel) { + ((AlipayTradeWapPayModel)model).setExtendParams(extendParams); + } + } + + public static AlipayClientWrapper getAlipayClientWrapper(AlipayIsvParams alipayIsvParams) { + return AlipayClientWrapper.buildAlipayClientWrapper(alipayIsvParams, null); + } + + + public static String appendErrCode(String code, String subCode){ + return StringUtils.defaultIfEmpty(subCode, code); //优先: subCode + } + + public static String appendErrMsg(String msg, String subMsg){ + + String result = null; + if(StringUtils.isNotEmpty(msg) && StringUtils.isNotEmpty(subMsg) ){ + result = msg + "【" + subMsg + "】"; + }else{ + result = StringUtils.defaultIfEmpty(subMsg, msg); + } + return CharSequenceUtil.maxLength(result, 253); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchApplymentService.java new file mode 100644 index 0000000..22a4647 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchApplymentService.java @@ -0,0 +1,299 @@ + +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.FileItem; +import com.alipay.api.domain.AlipayOpenAgentConfirmModel; +import com.alipay.api.domain.AlipayOpenAgentCreateModel; +import com.alipay.api.domain.ContactModel; +import com.alipay.api.domain.SignAddressInfo; +import com.alipay.api.request.AlipayOpenAgentConfirmRequest; +import com.alipay.api.request.AlipayOpenAgentCreateRequest; +import com.alipay.api.request.AlipayOpenAgentFacetofaceSignRequest; +import com.alipay.api.request.AlipayOpenAgentOrderQueryRequest; +import com.alipay.api.response.AlipayOpenAgentConfirmResponse; +import com.alipay.api.response.AlipayOpenAgentCreateResponse; +import com.alipay.api.response.AlipayOpenAgentFacetofaceSignResponse; +import com.alipay.api.response.AlipayOpenAgentOrderQueryResponse; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.AlipayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvsubMchParams; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.model.AlipayClientWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.net.URL; + +/** + * 支付宝接口进件 + * + * @author xiaoyu + * + * @date 2022/1/17 9:58 + */ +@Service +@Slf4j +public class AlipayMchApplymentService implements IIsvmchApplymentService { + + @Autowired private ConfigContextQueryService configContextQueryService; + @Autowired protected SysConfigService sysConfigService; + @Autowired protected MchInfoService mchInfoService; + + @Override + public MchApplyment firstApplyment(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + + // 发起商户是否为特约商户 + if (StringUtils.isEmpty(mchApplyment.getIsvNo())) { + throw new BizException("当前商户非特约商户"); + } + + // 查询当前商户信息 + MchInfo mchInfo = mchInfoService.getById(mchApplyment.getMchNo()); + + MchAppConfigContext context = new MchAppConfigContext(); + context.setMchInfo(mchInfo); + context.setMchType(mchInfo.getType()); + AlipayClientWrapper alipayClientWrapper = configContextQueryService.getAlipayClientWrapper(context); + if (alipayClientWrapper == null) { + throw new BizException("当前服务商未配置支付宝参数"); + } + + // 获取详细参数 + AlipayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), AlipayApplymentInfo.class); + + /* 发起进件 */ + if (AlipayApplymentInfo.PRODUCT_TYPE_OFFLINE.equals(info.getProductType())) { // 当面付 + result = toApplyOffline(info, alipayClientWrapper); + }else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("尚未支持该产品"); + } + result.setApplyDetailInfo(JSON.toJSONString(info)); //重新更新全量参数(包含imgCache) + + return result; + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + + // 查询当前商户信息 + MchInfo mchInfo = mchInfoService.getById(mchApplyment.getMchNo()); + + MchAppConfigContext context = new MchAppConfigContext(); + context.setMchInfo(mchInfo); + context.setMchType(mchInfo.getType()); + AlipayClientWrapper alipayClientWrapper = configContextQueryService.getAlipayClientWrapper(context); + if (alipayClientWrapper == null) { + throw new BizException("当前服务商未配置支付宝参数"); + } + // 调用查询接口 + AlipayOpenAgentOrderQueryRequest queryRequest = new AlipayOpenAgentOrderQueryRequest(); + // 调用进件接口 + JSONObject reqJSON = new JSONObject(); + reqJSON.put("batch_no", mchApplyment.getChannelApplyNo()); // 接入方商户号+申请编号 唯一 + queryRequest.setBizContent(reqJSON.toJSONString()); + log.info("请求支付宝进件查询接口参数: req={}", reqJSON); + AlipayOpenAgentOrderQueryResponse queryResponse = alipayClientWrapper.execute(queryRequest); + log.info("请求支付宝查询接口 code={}, msg={}, subCode={}, subMsg={}", queryResponse.getCode(), queryResponse.getMsg(), queryResponse.getSubCode(), queryResponse.getSubMsg()); + + // 创建返回对象 + MchApplyment result = new MchApplyment(); + // 业务异常 + if(!queryResponse.isSuccess()){ + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(queryResponse.getCode() + "[" + queryResponse.getMsg() + "]" + queryResponse.getSubCode() + "[" + queryResponse.getSubMsg() + "]"); + return result; + } + + // 审核状态 + if(queryResponse.isSuccess()){ + if ("MERCHANT_CONFIRM".equals(queryResponse.getOrderStatus())) { // 待商户确认 + result.setState(MchApplyment.STATE_WAIT_SIGN); + // 放置请求ID + result.setChannelApplyNo(queryResponse.getAgentAppId()); + // 商户签约地址 + result.setApplyErrorInfo(queryResponse.getConfirmUrl()); + }else if ("MERCHANT_CONFIRM_SUCCESS".equals(queryResponse.getOrderStatus())) { // 商户确认成功 + result.setState(MchApplyment.STATE_SUCCESS); + + }else if ("MERCHANT_AUDITING".equals(queryResponse.getOrderStatus())) { // 审核中 + result.setState(MchApplyment.STATE_AUDITING); + + }else { // 异常失败 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(queryResponse.getCode() + "[" + queryResponse.getMsg() + "]" + queryResponse.getSubCode() + "[" + queryResponse.getSubMsg() + "]" + "[" + queryResponse.getRejectReason() + "]"); + } + + // 封装支付参数 + AlipayIsvsubMchParams mchParams = new AlipayIsvsubMchParams(); + mchParams.setAppAuthToken(queryResponse.getMerchantPid()); + result.setSuccResParameter(JSON.toJSONString(mchParams)); + return result; + }else{ + + // 审核中 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return result; + + } + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + private MchApplyment toApplyOffline(AlipayApplymentInfo info, AlipayClientWrapper alipayClientWrapper) { + // 创建返回对象 + MchApplyment result = new MchApplyment(); + String batchNo = ""; + try { + /* 1.开启事务 */ + AlipayOpenAgentCreateRequest openRequest = new AlipayOpenAgentCreateRequest(); + AlipayOpenAgentCreateModel openModel = new AlipayOpenAgentCreateModel(); + + ContactModel contactModel = new ContactModel(); + contactModel.setContactName(info.getContactName()); // 联系人名称 + contactModel.setContactMobile(info.getContactPhone()); // 联系人手机号码 + contactModel.setContactEmail(info.getContactEmail()); // 联系人邮箱 + openModel.setContactInfo(contactModel); + + openModel.setAccount(info.getAccountNo()); + openRequest.setBizModel(openModel); + + AlipayOpenAgentCreateResponse response = alipayClientWrapper.execute(openRequest); + log.info("【1】开启代商户签约,开启事务:code={}, msg={}", response.getCode(), response.getMsg()); + + if (!response.isSuccess()) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(response.getCode() + "[" + response.getMsg() + "]" + response.getSubCode() + "[" + response.getSubMsg() + "]"); + log.error("支付宝【当面付】进件开启事务失败;msg={}, subMsg={}", response.getMsg(), response.getSubMsg()); + return result; + } + if (!"init".equals(response.getBatchStatus())) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(response.getCode() + "[" + response.getMsg() + "]" + response.getSubCode() + "[" + response.getSubMsg() + "]"); + log.error("支付宝【当面付】进件batchStatus状态不等于init,提交事务失败"); + return result; + } + batchNo = response.getBatchNo(); + + // 放置请求ID + result.setChannelApplyNo(batchNo); + /* 2.发起待签约 */ + AlipayOpenAgentFacetofaceSignRequest offRequest = new AlipayOpenAgentFacetofaceSignRequest(); + + offRequest.setBatchNo(batchNo); // 代商户操作事务编号 + + offRequest.setMccCode(info.getMccCode()); // 所属经营类目编码 + + // 特殊资质证书 + if (StringUtils.isNotEmpty(info.getSpecialLicenseImg())) { + //下载文件 & 转换为byte数组格式 + byte[] imgFileByteArray = IOUtils.toByteArray(new URL(info.getSpecialLicenseImg())); + offRequest.setSpecialLicensePic(new FileItem("1.png", imgFileByteArray)); + } + + // 服务费率 + offRequest.setRate(info.convertPaywayFeeList2String()); + + // 营业执照编号 + offRequest.setBusinessLicenseNo(info.getLicenseNo()); + + // 营业执照照片 + if (StringUtils.isNotEmpty(info.getLicenseImg())) { + //下载文件 & 转换为byte数组格式 + byte[] imgFileByteArray = IOUtils.toByteArray(new URL(info.getLicenseImg())); + offRequest.setBusinessLicensePic(new FileItem("1.png", imgFileByteArray)); + } + // 营业期限 + if (StringUtils.isNotEmpty(info.getLicenseEffectEnd())) { + if ("长期".equals(info.getLicenseEffectEnd())) { + offRequest.setLongTerm(true); + }else { + offRequest.setDateLimitation(info.getLicenseEffectEnd()); + } + } + // 店铺门头照 + if (StringUtils.isNotEmpty(info.getStoreOuterImg())) { + //下载文件 & 转换为byte数组格式 + byte[] imgFileByteArray = IOUtils.toByteArray(new URL(info.getStoreOuterImg())); + offRequest.setShopSignBoardPic(new FileItem("1.png", imgFileByteArray)); + } + // 门店名称 + offRequest.setShopName(info.getMchFullName()); + + // 店铺内景照 + if (StringUtils.isNotEmpty(info.getStoreInnerImg())) { + //下载文件 & 转换为byte数组格式 + byte[] imgFileByteArray = IOUtils.toByteArray(new URL(info.getStoreInnerImg())); + offRequest.setShopScenePic(new FileItem("1.png", imgFileByteArray)); + } + + // 营业执照法人手机号 + offRequest.setBusinessLicenseMobile(info.getContactPhone()); + + // 店铺地址 + SignAddressInfo addressInfo = new SignAddressInfo(); + addressInfo.setCountryCode("156"); + addressInfo.setProvinceCode(info.getAreaCode().getString(0)); // 省编码 + addressInfo.setCityCode(info.getAreaCode().getString(1)); // 市编码 + addressInfo.setDistrictCode(info.getAreaCode().getString(2)); // 区编码 + addressInfo.setDetailAddress(info.getAddress()); // 详细地址 + offRequest.setShopAddress(addressInfo); + + AlipayOpenAgentFacetofaceSignResponse signResponse = alipayClientWrapper.execute(offRequest); + log.info("【2】待签约当面付:code={}, msg={}, subCode={}, subMsg={}", signResponse.getCode(), signResponse.getMsg(), signResponse.getSubCode(), signResponse.getSubMsg()); + if (!signResponse.isSuccess()) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(signResponse.getCode() + "[" + signResponse.getMsg() + "]" + signResponse.getSubCode() + "[" + signResponse.getSubMsg() + "]"); + log.error("发起待签约失败:code={}, msg={}, subCode={}, subMsg={}", signResponse.getCode(), signResponse.getMsg(), signResponse.getSubCode(), signResponse.getSubMsg()); + return result; + } + + /* 3.提交待签约事务 */ + AlipayOpenAgentConfirmRequest confirmRequest = new AlipayOpenAgentConfirmRequest(); + AlipayOpenAgentConfirmModel confirmModel = new AlipayOpenAgentConfirmModel(); + confirmModel.setBatchNo(batchNo); + confirmRequest.setBizModel(confirmModel); + AlipayOpenAgentConfirmResponse confirmResponse = alipayClientWrapper.execute(confirmRequest); + log.info("【3】提交待签约事务:code={}, msg={}, subCode={}, subMsg={}", confirmResponse.getCode(), confirmResponse.getMsg(), confirmResponse.getSubCode(), confirmResponse.getSubMsg()); + if (!confirmResponse.isSuccess()) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); // 失败 + result.setApplyErrorInfo(confirmResponse.getCode() + "[" + confirmResponse.getMsg() + "]" + confirmResponse.getSubCode() + "[" + confirmResponse.getSubMsg() + "]"); + log.error("提交待签约事务失败:code={}, msg={}, subCode={}, subMsg={}", confirmResponse.getCode(), confirmResponse.getMsg(), confirmResponse.getSubCode(), confirmResponse.getSubMsg()); + return result; + } + result.setState(MchApplyment.STATE_AUDITING); // 审核中 + }catch (Exception e) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("进件异常:{}", e.getMessage()); + } + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchAutoAuthService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchAutoAuthService.java new file mode 100644 index 0000000..f54876b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayMchAutoAuthService.java @@ -0,0 +1,52 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.AlipayOpenAuthTokenAppModel; +import com.alipay.api.request.AlipayOpenAuthTokenAppRequest; +import com.alipay.api.response.AlipayOpenAuthTokenAppResponse; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IMchAutoAuthService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.thirdparty.model.AlipayClientWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 支付宝: 商户授权实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service +@Slf4j +public class AlipayMchAutoAuthService implements IMchAutoAuthService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + + @Override + public JSONObject mchAuth(MchAppConfigContext mchAppConfigContext, String appAuthCode) { + + AlipayClientWrapper alipayClientWrapper = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext); + + AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest(); + AlipayOpenAuthTokenAppModel model = new AlipayOpenAuthTokenAppModel(); + model.setGrantType("authorization_code"); + model.setCode(appAuthCode); + request.setBizModel(model); + + // expiresIn: 该字段已作废,应用令牌长期有效,接入方不需要消费该字段 + // reExpiresIn: 刷新令牌的有效时间(从接口调用时间作为起始时间),单位到秒 + // DateUtil.offsetSecond(new Date(), Integer.parseInt(resp.getExpiresIn())); + AlipayOpenAuthTokenAppResponse resp = alipayClientWrapper.execute(request); + if(!resp.isSuccess()){ + throw new BizException(AlipayKit.appendErrMsg(resp.getMsg(), resp.getSubMsg())); + } + + return (JSONObject) JSON.toJSON(resp); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayOpenSpOperationService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayOpenSpOperationService.java new file mode 100644 index 0000000..39d2157 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayOpenSpOperationService.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.AlipayOpenSpOperationApplyModel; +import com.alipay.api.domain.AlipayOpenSpOperationQrcodeQueryModel; +import com.alipay.api.domain.AlipayOpenSpOperationResultQueryModel; +import com.alipay.api.request.AlipayOpenSpOperationApplyRequest; +import com.alipay.api.request.AlipayOpenSpOperationQrcodeQueryRequest; +import com.alipay.api.request.AlipayOpenSpOperationResultQueryRequest; +import com.alipay.api.response.AlipayOpenSpOperationApplyResponse; +import com.alipay.api.response.AlipayOpenSpOperationQrcodeQueryResponse; +import com.alipay.api.response.AlipayOpenSpOperationResultQueryResponse; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayOpenSpOperationService; +import com.jeequan.jeepay.core.model.alipay.AlipaySpOperationInfo; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* +* 支付宝服务商代运营授权 +* +* @author zx +* +* @date 2023/3/8 15:13 +*/ +@Slf4j +@Service +public class AlipayOpenSpOperationService implements IAlipayOpenSpOperationService { + + @Override + public JSONObject querySpOperationQrcode(AlipayIsvParams alipayIsvParams, String alipayAccount) { + AlipayOpenSpOperationQrcodeQueryRequest request = new AlipayOpenSpOperationQrcodeQueryRequest(); + AlipayOpenSpOperationQrcodeQueryModel model = new AlipayOpenSpOperationQrcodeQueryModel(); + model.setOutBizNo(IdUtil.fastSimpleUUID()); // 外部操作流水,由服务商自定义,需确保每次操作唯一 + model.setOperateType("OPERATION_AUTH"); // OPERATION_AUTH:代运营授权,支持间连、直连商户。ACCOUNT_BIND:账号绑定,仅支持间连商户。 + model.setAlipayAccount(alipayAccount); + model.setAccessProductCode("OPENAPI_AUTH_DEFAULT"); + request.setBizModel(model); + + AlipayOpenSpOperationQrcodeQueryResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + return (JSONObject) JSON.toJSON(response); + } + + @Override + public JSONObject applySpOperation(AlipayIsvParams alipayIsvParams, String alipayAccount){ + AlipayOpenSpOperationApplyRequest request = new AlipayOpenSpOperationApplyRequest(); + AlipayOpenSpOperationApplyModel model = new AlipayOpenSpOperationApplyModel(); + model.setOutBizNo(IdUtil.fastSimpleUUID()); + model.setOperateType("OPERATION_AUTH"); + model.setAlipayAccount(alipayAccount); + model.setAccessProductCode("OPENAPI_AUTH_DEFAULT"); + request.setBizModel(model); + + AlipayOpenSpOperationApplyResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + return (JSONObject) JSON.toJSON(response); + } + + @Override + public AlipaySpOperationInfo querySpOperationResult(AlipayIsvParams alipayIsvParams, String alipayAccount){ + AlipayOpenSpOperationResultQueryRequest request = new AlipayOpenSpOperationResultQueryRequest(); + AlipayOpenSpOperationResultQueryModel model = new AlipayOpenSpOperationResultQueryModel(); + model.setOperateType("OPERATION_AUTH"); + model.setAlipayAccount(alipayAccount); + model.setAccessProductCode("OPENAPI_AUTH_DEFAULT"); + request.setBizModel(model); + + AlipayOpenSpOperationResultQueryResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + + AlipaySpOperationInfo operationInfo = new AlipaySpOperationInfo(); + BeanUtil.copyProperties(response, operationInfo); + + return operationInfo; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderCloseService.java new file mode 100644 index 0000000..287b8f5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderCloseService.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alipay.api.domain.AlipayTradeCloseModel; +import com.alipay.api.request.AlipayTradeCloseRequest; +import com.alipay.api.response.AlipayTradeCloseResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 支付宝 关闭订单接口实现类 + * + * @author xiaoyu + * + * @date 2022/1/25 11:17 + */ +@Service +public class AlipayPayOrderCloseService implements IPayOrderCloseService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AlipayTradeCloseRequest req = new AlipayTradeCloseRequest(); + + // 商户订单号,商户网站订单系统中唯一订单号,必填 + AlipayTradeCloseModel model = new AlipayTradeCloseModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + req.setBizModel(model); + + //通用字段 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + AlipayTradeCloseResponse resp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + + // 返回状态成功 + if (resp.isSuccess()) { + return ChannelRetMsg.confirmSuccess(resp.getTradeNo()); + }else { + return ChannelRetMsg.sysError(resp.getSubMsg()); + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderQueryService.java new file mode 100644 index 0000000..c389270 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPayOrderQueryService.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alipay.api.domain.AlipayTradeQueryModel; +import com.alipay.api.request.AlipayTradeQueryRequest; +import com.alipay.api.response.AlipayTradeQueryResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 支付宝 查单接口实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:20 +*/ +@Service +public class AlipayPayOrderQueryService implements IPayOrderQueryService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AlipayTradeQueryRequest req = new AlipayTradeQueryRequest(); + + // 商户订单号,商户网站订单系统中唯一订单号,必填 + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + req.setBizModel(model); + + //通用字段 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + AlipayTradeQueryResponse resp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + String result = resp.getTradeStatus(); + + if("TRADE_SUCCESS".equals(result)) { + return ChannelRetMsg.confirmSuccess(resp.getTradeNo(), resp.getTradeNo(), payOrder.getPayOrderId(),null); //支付成功 + }else if("WAIT_BUYER_PAY".equals(result)) { + return ChannelRetMsg.waiting(); //支付中 + } + return ChannelRetMsg.waiting(); //支付中 + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPaymentService.java new file mode 100644 index 0000000..03cea02 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayPaymentService.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import org.springframework.stereotype.Service; + +/* +* 支付接口: 支付宝官方 +* 支付方式: 自适应 +* +* @author terrfly +* +* @date 2021/6/8 17:19 +*/ +@Service +public class AlipayPaymentService extends AbstractPaymentService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayRefundService.java new file mode 100644 index 0000000..84d2680 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayRefundService.java @@ -0,0 +1,118 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel; +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; +import com.alipay.api.response.AlipayTradeRefundResponse; +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import org.springframework.stereotype.Service; + +/* +* 退款接口: 支付宝官方 +* +* @author terrfly +* +* @date 2021/6/17 9:38 +*/ +@Service +public class AlipayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + model.setOutTradeNo(refundOrder.getPayOrderId()); + model.setTradeNo(refundOrder.getChannelPayOrderNo()); + model.setOutRequestNo(refundOrder.getRefundOrderId()); + model.setRefundAmount(AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount().toString())); + model.setRefundReason(refundOrder.getRefundReason()); + request.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + + AlipayTradeRefundResponse response = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request); + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelAttach(response.getBody()); + + // 调用成功 + if(response.isSuccess()){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getSubCode()); + channelRetMsg.setChannelErrMsg(response.getSubMsg()); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); + model.setTradeNo(refundOrder.getChannelPayOrderNo()); + model.setOutTradeNo(refundOrder.getPayOrderId()); + model.setOutRequestNo(refundOrder.getRefundOrderId()); + request.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + + AlipayTradeFastpayRefundQueryResponse response = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request); + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelAttach(response.getBody()); + + // 调用成功 & 金额相等 (传入不存在的outRequestNo支付宝仍然返回响应成功只是数据不存在, 调用isSuccess() 仍是成功, 此处需判断金额是否相等) + Long channelRefundAmount = response.getRefundAmount() == null ? null : Long.parseLong(AmountUtil.convertDollar2Cent(response.getRefundAmount())); + if(response.isSuccess() && refundOrder.getRefundAmount().equals(channelRefundAmount)){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + + } + + return channelRetMsg; + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } + + /** + * 退款权限 + * @param settleType + * @param applyId + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayShopService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayShopService.java new file mode 100644 index 0000000..1b9385d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayShopService.java @@ -0,0 +1,176 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.*; +import com.alipay.api.request.*; +import com.alipay.api.response.*; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayShopService; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 蚂蚁店铺管理接口 +* +* @author zx +* +* @date 2023/3/8 15:13 +*/ +@Slf4j +@Service +public class AlipayShopService implements IAlipayShopService { + + @Override + public MchStore query(AlipayIsvParams alipayIsvParams, String storeId, String ipRoleId) { + AntMerchantExpandShopQueryRequest request = new AntMerchantExpandShopQueryRequest(); + AntMerchantExpandShopQueryModel model = new AntMerchantExpandShopQueryModel(); + + model.setStoreId(storeId); // 系统门店ID + model.setIpRoleId(ipRoleId); // 直连开店场景,填写商户pid + request.setBizModel(model); + + AntMerchantExpandShopQueryResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + // 转换为商户门店信息 + MchStore mchStore = new MchStore(); + mchStore.setAlipayShopId(response.getShopId()); + mchStore.setStoreName(response.getShopName()); + mchStore.setContactPhone(response.getContactMobile()); + mchStore.addExt("shopCategory", response.getNewShopCategory()); + mchStore.addExt("shopType", response.getShopType()); + + AddressInfo businessAddress = response.getBusinessAddress(); + JSONArray jsonArray = new JSONArray(); + jsonArray.add(businessAddress.getProvinceCode()); + jsonArray.add(businessAddress.getCityCode()); + jsonArray.add(businessAddress.getDistrictCode()); + mchStore.setAreaCode(jsonArray); + mchStore.setAddress(businessAddress.getAddress()); + mchStore.setLat(businessAddress.getLatitude()); + mchStore.setLng(businessAddress.getLongitude()); + + return mchStore; + } + + @Override + public MchStore create(AlipayIsvParams alipayIsvParams, MchStore mchStore, String ipRoleId){ + AntMerchantExpandShopCreateRequest request = new AntMerchantExpandShopCreateRequest(); + AntMerchantExpandShopCreateModel model = new AntMerchantExpandShopCreateModel(); + + // 经营地址 + AddressInfo businessAddress = new AddressInfo(); + businessAddress.setProvinceCode(mchStore.getAreaCode().getString(0)); + businessAddress.setCityCode(mchStore.getAreaCode().getString(1)); + businessAddress.setDistrictCode(mchStore.getAreaCode().getString(2)); + businessAddress.setAddress(mchStore.getAddress()); + model.setBusinessAddress(businessAddress); + + if (mchStore.getExt() != null) { + if (StringUtils.isNotBlank(mchStore.getExt().getString("shopCategory"))) { + model.setShopCategory(mchStore.getExt().getString("shopCategory").split("_")[1]); // 新版门店类目标准二级类目code + } + model.setShopType(mchStore.getExt().getString("shopType")); // 店铺经营类型,01表示直营,02表示加盟 + } + + model.setStoreId(mchStore.getStoreId() + ""); // 外部门店ID + model.setIpRoleId(ipRoleId); + model.setShopName(mchStore.getStoreName()); + model.setContactMobile(mchStore.getContactPhone()); + request.setBizModel(model); + + AntMerchantExpandShopCreateResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("蚂蚁店铺创建响应,storeId={},response={}", mchStore.getStoreId(), JSONObject.toJSONString(response)); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + MchStore result = new MchStore(); + result.setAlipayShopCreateId(response.getOrderId()); + + return result; + } + + @Override + public MchStore update(AlipayIsvParams alipayIsvParams, MchStore mchStore){ + AntMerchantExpandShopModifyRequest request = new AntMerchantExpandShopModifyRequest(); + AntMerchantExpandShopModifyModel model = new AntMerchantExpandShopModifyModel(); + + model.setShopId(mchStore.getAlipayShopId()); + + // 经营地址 + AddressInfo businessAddress = new AddressInfo(); + businessAddress.setProvinceCode(mchStore.getAreaCode().getString(0)); + businessAddress.setCityCode(mchStore.getAreaCode().getString(1)); + businessAddress.setDistrictCode(mchStore.getAreaCode().getString(2)); + businessAddress.setAddress(mchStore.getAddress()); + model.setBusinessAddress(businessAddress); + + if (mchStore.getExt() != null) { + if (StringUtils.isNotBlank(mchStore.getExt().getString("shopCategory")) && mchStore.getExt().getString("shopCategory").contains("_")) { + model.setShopCategory(mchStore.getExt().getString("shopCategory").split("_")[1]); // 新版门店类目标准二级类目code + }else { + model.setShopCategory(mchStore.getExt().getString("shopCategory")); // 新版门店类目标准二级类目code + } + } + + model.setShopName(mchStore.getStoreName()); + model.setContactMobile(mchStore.getContactPhone()); + request.setBizModel(model); + + AntMerchantExpandShopModifyResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("蚂蚁店铺修改响应,storeId={},response={}", mchStore.getStoreId(), JSONObject.toJSONString(response)); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + MchStore result = new MchStore(); + result.setAlipayShopCreateId(response.getOrderId()); + + return result; + } + + @Override + public void close(AlipayIsvParams alipayIsvParams, String alipayShopId) { + AntMerchantExpandShopCloseRequest request = new AntMerchantExpandShopCloseRequest(); + AntMerchantExpandShopCloseModel model = new AntMerchantExpandShopCloseModel(); + model.setShopId(alipayShopId); + + request.setBizModel(model); + + AntMerchantExpandShopCloseResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + } + + @Override + public MchStore createResultQuery(AlipayIsvParams alipayIsvParams, String orderId){ + AntMerchantExpandOrderQueryRequest request = new AntMerchantExpandOrderQueryRequest(); + AntMerchantExpandOrderQueryModel model = new AntMerchantExpandOrderQueryModel(); + model.setOrderId(orderId); + request.setBizModel(model); + + AntMerchantExpandOrderQueryResponse response = AlipayKit.getAlipayClientWrapper(alipayIsvParams).getAlipayClient().execute(request); + log.info("蚂蚁店铺申请单查询接口响应,orderId={},response={}", orderId, JSONObject.toJSONString(response)); + if (!response.isSuccess()) { + throw new BizException(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + + MchStore result = new MchStore(); + if (StringUtils.isNotBlank(response.getExtInfo())) { + JSONObject extInfo = JSONObject.parseObject(response.getExtInfo()); + result.setAlipayShopId(extInfo.getString("SHOP_ID")); + } + result.setAlipayShopStatus(response.getStatus()); + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferNoticeService.java new file mode 100644 index 0000000..91e02f8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferNoticeService.java @@ -0,0 +1,113 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.internal.util.AlipaySignature; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/* +* 支付宝 转账回调接口实现类 +* +* @author zx +* +* @date 2021/21/01 17:16 +*/ +@Service +@Slf4j +public class AlipayTransferNoticeService extends AbstractTransferNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId) { + + try { + + JSONObject params = getReqParamJSON(); + log.info("【支付宝转账】回调通知参数:{}", params.toJSONString()); + + JSONObject bizContent = JSONObject.parseObject(params.getString("biz_content")); + + String transferId = bizContent.getString("out_biz_no"); + return MutablePair.of(transferId, params); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, TransferOrder transferOrder) { + + String logPrefix = "【支付宝转账通知】"; + + try { + //配置参数获取 + Byte useCert = null; + String alipaySignType, alipayPublicCert, alipayPublicKey; + // 获取支付参数 + AlipayIsvParams alipayParams = (AlipayIsvParams) configContextQueryService.queryTransferIsvParams(transferOrder.getIsvNo(), getIfCode()); + + useCert = alipayParams.getUseCert(); + alipaySignType = alipayParams.getSignType(); + alipayPublicCert = alipayParams.getAlipayPublicCert(); + alipayPublicKey = alipayParams.getAlipayPublicKey(); + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + JSONObject bizContent = JSONObject.parseObject(jsonParams.getString("biz_content")); + + boolean verifyResult; + if(useCert != null && useCert == CS.YES){ //证书方式 + + verifyResult = AlipaySignature.rsaCertCheckV1(jsonParams.toJavaObject(Map.class), getCertFilePath(alipayPublicCert), + AlipayConfig.CHARSET, alipaySignType); + + }else{ + verifyResult = AlipaySignature.rsaCheckV1(jsonParams.toJavaObject(Map.class), alipayPublicKey, AlipayConfig.CHARSET, alipaySignType); + } + + //验签失败 + if(!verifyResult){ + log.error("{},验签失败", logPrefix); + throw ResponseException.buildText("ERROR"); + } + + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("SUCCESS"); + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setResponseEntity(okResponse); // 响应数据 + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认转账中 + + // 成功-SUCCESS + String status = bizContent.getString("status"); + if("SUCCESS".equals(status)){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + } + + return channelRetMsg; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferService.java new file mode 100644 index 0000000..39823ab --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/AlipayTransferService.java @@ -0,0 +1,194 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay; + +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayFundTransCommonQueryModel; +import com.alipay.api.domain.AlipayFundTransUniTransferModel; +import com.alipay.api.domain.ExtendParams; +import com.alipay.api.domain.Participant; +import com.alipay.api.request.AlipayFundTransCommonQueryRequest; +import com.alipay.api.request.AlipayFundTransUniTransferRequest; +import com.alipay.api.response.AlipayFundTransCommonQueryResponse; +import com.alipay.api.response.AlipayFundTransUniTransferResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** +* 转账接口: 支付宝官方 +* +* @author terrfly +* +* @date 2021/8/11 14:05 +*/ +@Slf4j +@Service +public class AlipayTransferService extends AbstractTransferService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public boolean isSupport(String entryType) { + + // 支付宝账户 + if(TransferOrder.ENTRY_ALIPAY_CASH.equals(entryType)){ + return true; + } + + return false; + } + + @Override + public String preCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + super.preCheck(bizRQ, transferOrder); + + /* + * 支付宝新版转账接口:不支持服务商模式 ( 不存在 app_auth_token 参数了 ) + * 旧版文档地址: https://opendocs.alipay.com/open/309/alipay.fund.trans.toaccount.transfer + * 新版文档地址: https://opendocs.alipay.com/open/02byuo?ref=api&scene=ca56bca529e64125a2786703c6192d41 + */ + if(transferOrder.getMchType() == CS.MCH_TYPE_ISVSUB){ + return "支付宝子商户暂不支持转账业务"; + } + + return null; + } + + @Override + public ChannelRetMsg transfer(TransferOrderRQ bizRQ, TransferOrder transferOrder){ + + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); + model.setTransAmount(AmountUtil.convertCent2Dollar(transferOrder.getAmount())); //转账金额,单位:元。 + model.setOutBizNo(transferOrder.getTransferId()); //商户转账唯一订单号 + model.setRemark(transferOrder.getTransferDesc()); //转账备注 + model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD + model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER。 + model.setOrderTitle("转账"); // 转账业务的标题,用于在支付宝用户的账单里显示。 + model.setBusinessParams(transferOrder.getChannelExtra()); // 转账业务请求的扩展参数 {\"payer_show_name_use_alias\":\"xx公司\"} + + Participant accPayeeInfo = new Participant(); + accPayeeInfo.setName(StringUtils.defaultString(transferOrder.getAccountName(), null)); //收款方真实姓名 + accPayeeInfo.setIdentityType("ALIPAY_LOGON_ID"); //ALIPAY_USERID: 支付宝用户ID ALIPAY_LOGONID:支付宝登录账号 + accPayeeInfo.setIdentity(transferOrder.getAccountNo()); //收款方账户 + model.setPayeeInfo(accPayeeInfo); + + request.setBizModel(model); + + TransferSubjectEntity transferSubjectFq = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + + //统一放置 isv接口必传信息 + // 获取支付参数 + AlipayIsvParams isvParams = (AlipayIsvParams) configContextQueryService.queryTransferIsvParams(transferSubjectFq); + + // 服务商信息 + ExtendParams extendParams = new ExtendParams(); + extendParams.setSysServiceProviderId(isvParams.getPid()); + +// if(model instanceof AlipayTradePayModel) { +// ((AlipayTradePayModel)model).setExtendParams(extendParams); +// } else if(model instanceof AlipayTradeAppPayModel) { +// ((AlipayTradeAppPayModel)model).setExtendParams(extendParams); +// } else if(model instanceof AlipayTradeCreateModel) { +// ((AlipayTradeCreateModel)model).setExtendParams(extendParams); +// } else if(model instanceof AlipayTradePagePayModel) { +// ((AlipayTradePagePayModel)model).setExtendParams(extendParams); +// } else if(model instanceof AlipayTradePrecreateModel) { +// ((AlipayTradePrecreateModel)model).setExtendParams(extendParams); +// } else if(model instanceof AlipayTradeWapPayModel) { +// ((AlipayTradeWapPayModel)model).setExtendParams(extendParams); +// } + + request.putOtherTextParam("app_auth_token", isvParams.getAppAuthToken()); + + // 调起支付宝接口 + AlipayFundTransUniTransferResponse response; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + try { + DefaultAlipayClient alipayClient = new DefaultAlipayClient(isvParams.getConfig()); + response = alipayClient.certificateExecute(request); + channelRetMsg.setChannelAttach(response.getBody()); + + // 调用成功 + if(response.isSuccess()){ + if ("SUCCESS".equals(response.getStatus())) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setChannelOrderId(response.getOrderId()); + return channelRetMsg; + }else if ("FAIL".equals(response.getStatus())) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(response.getCode(), response.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + return channelRetMsg; + }else { + return ChannelRetMsg.waiting(); + } + }else{ + //若 系统繁忙, 无法确认结果 + if("SYSTEM_ERROR".equalsIgnoreCase(response.getSubCode())){ + return ChannelRetMsg.waiting(); + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getSubCode()); + channelRetMsg.setChannelErrMsg(response.getSubMsg()); + } + } catch (Exception e) { + log.info("支付宝请求异常", e); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg("支付宝请求异常"); + } + + + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) { + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); + model.setProductCode(TransferOrder.ENTRY_BANK_CARD.equals(transferOrder.getEntryType()) ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD"); + model.setBizScene("DIRECT_TRANSFER"); + model.setOutBizNo(transferOrder.getTransferId()); // 商户转账唯一订单号 + + AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model); + request.setBizModel(model); + + // 调起支付宝接口 + AlipayFundTransCommonQueryResponse response = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request); + if (response.isSuccess()) { + // SUCCESS,明确成功 + if("SUCCESS".equalsIgnoreCase(response.getStatus())){ + return ChannelRetMsg.confirmSuccess(response.getOrderId()); + } + // REFUND:退票(适用于"单笔转账到银行卡"); FAIL:失败(适用于"单笔转账到银行卡") + else if ("REFUND".equalsIgnoreCase(response.getStatus()) || "FAIL".equalsIgnoreCase(response.getStatus())){ + return ChannelRetMsg.confirmFail(response.getErrorCode(), response.getFailReason()); + } else{ + return ChannelRetMsg.waiting(); + } + } else { + // 如果查询单号对应的数据不存在,那么数据不存在的原因可能是:(1)付款还在处理中;(2)付款处理失败导致付款订单没有落地,务必再次查询确认此次付款的结果。 + if("ORDER_NOT_EXIST".equalsIgnoreCase(response.getSubCode())){ + return ChannelRetMsg.waiting(); + } + return ChannelRetMsg.confirmFail(AlipayKit.appendErrCode(response.getCode(), response.getSubCode()), AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg())); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliApp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliApp.java new file mode 100644 index 0000000..96c0279 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliApp.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeAppPayModel; +import com.alipay.api.request.AlipayTradeAppPayRequest; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliAppOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝 APP支付 +* +* @author terrfly +* +* @date 2021/6/8 17:20 +*/ +@Service("alipayPaymentByAliAppService") //Service Name需保持全局唯一性 +public class AliApp extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AlipayTradeAppPayRequest req = new AlipayTradeAppPayRequest(); + AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + + String payData = null; + + // sdk方式需自行拦截接口异常信息 + try { + payData = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().sdkExecute(req).getBody(); + } catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + + // 构造函数响应数据 + AliAppOrderRS res = ApiResBuilder.buildSuccess(AliAppOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(payData); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + res.setPayData(payData); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliBar.java new file mode 100644 index 0000000..03d372f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliBar.java @@ -0,0 +1,101 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradePayModel; +import com.alipay.api.request.AlipayTradePayRequest; +import com.alipay.api.response.AlipayTradePayResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 支付宝 条码支付 + * + * @author terrfly + * + * @date 2021/6/8 17:20 + */ +@Service("alipayPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + + AlipayTradePayRequest req = new AlipayTradePayRequest(); + AlipayTradePayModel model = new AlipayTradePayModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setScene("bar_code"); //条码支付 bar_code ; 声波支付 wave_code + model.setAuthCode(bizRQ.getAuthCode().trim()); //支付授权码 + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + //调起支付宝 (如果异常, 将直接跑出 ChannelException ) + AlipayTradePayResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + + // 构造函数响应数据 + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + channelRetMsg.setChannelOrderId(alipayResp.getTradeNo()); + channelRetMsg.setPlatformOrderNo(alipayResp.getTradeNo()); + channelRetMsg.setPlatformMchOrderNo(payOrder.getPayOrderId()); + channelRetMsg.setChannelUserId(alipayResp.getBuyerUserId()); //渠道用户标识 + + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + + //当条码重复发起时,支付宝返回的code = 10003, subCode = null [等待用户支付], 此时需要特殊判断 = = 。 + if("10000".equals(alipayResp.getCode()) && alipayResp.isSuccess()){ //支付成功, 更新订单成功 || 等待支付宝的异步回调接口 + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + + }else if("10003".equals(alipayResp.getCode())){ //10003 表示为 处理中, 例如等待用户输入密码 + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }else{ //其他状态, 表示下单失败 + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + + return res; + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliJsapi.java new file mode 100644 index 0000000..d96e6b3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliJsapi.java @@ -0,0 +1,89 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradeCreateModel; +import com.alipay.api.request.AlipayTradeCreateRequest; +import com.alipay.api.response.AlipayTradeCreateResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 支付宝 jsapi支付 + * + * @author terrfly + * + * @date 2021/6/8 17:20 + */ +@Service("alipayPaymentByJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + + AlipayTradeCreateRequest req = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = new AlipayTradeCreateModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + model.setBuyerId(bizRQ.getBuyerUserId()); + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + //调起支付宝 (如果异常, 将直接跑出 ChannelException ) + AlipayTradeCreateResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + + // 构造函数响应数据 + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + res.setAlipayTradeNo(alipayResp.getTradeNo()); + + channelRetMsg.setChannelOrderId(alipayResp.getTradeNo()); + if(alipayResp.isSuccess()){ //业务处理成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliLite.java new file mode 100644 index 0000000..35b5bdc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliLite.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradeCreateModel; +import com.alipay.api.request.AlipayTradeCreateRequest; +import com.alipay.api.response.AlipayTradeCreateResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 支付宝 小程序支付 + * + * @author terrfly + * + * @date 2021/6/8 17:20 + */ +@Service("alipayPaymentByLiteService") //Service Name需保持全局唯一性 +public class AliLite extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + + AlipayTradeCreateRequest req = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = new AlipayTradeCreateModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + model.setBuyerId(bizRQ.getBuyerUserId()); + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + AlipayOauth2Params oauth2Params = (AlipayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + model.setProductCode("JSAPI_PAY"); + model.setOpAppId(oauth2Params.getLiteParams().getAppId()); + + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + //调起支付宝 (如果异常, 将直接跑出 ChannelException ) + AlipayTradeCreateResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + + // 构造函数响应数据 + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + res.setAlipayTradeNo(alipayResp.getTradeNo()); + + channelRetMsg.setChannelOrderId(alipayResp.getTradeNo()); + if(alipayResp.isSuccess()){ //业务处理成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliPc.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliPc.java new file mode 100644 index 0000000..88c4c96 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliPc.java @@ -0,0 +1,80 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePagePayModel; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliPcOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliPcOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝 PC支付 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service("alipayPaymentByAliPcService") //Service Name需保持全局唯一性 +public class AliPc extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliPcOrderRQ bizRQ = (AliPcOrderRQ) rq; + + AlipayTradePagePayRequest req = new AlipayTradePagePayRequest(); + AlipayTradePagePayModel model = new AlipayTradePagePayModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + model.setProductCode("FAST_INSTANT_TRADE_PAY"); + model.setQrPayMode("2"); //订单码-跳转模式 + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setReturnUrl(getReturnUrl()); // 同步跳转地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + // 构造函数响应数据 + AliPcOrderRS res = ApiResBuilder.buildSuccess(AliPcOrderRS.class); + + try { + if(CS.PAY_DATA_TYPE.FORM.equals(bizRQ.getPayDataType())){ + res.setFormContent(configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().pageExecute(req).getBody()); + }else{ + res.setPayUrl(configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().pageExecute(req, "GET").getBody()); + } + }catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliQr.java new file mode 100644 index 0000000..af1b800 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliQr.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradePrecreateModel; +import com.alipay.api.request.AlipayTradePrecreateRequest; +import com.alipay.api.response.AlipayTradePrecreateResponse; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝 QR支付 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service("alipayPaymentByAliQrService") //Service Name需保持全局唯一性 +public class AliQr extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliQrOrderRQ aliQrOrderRQ = (AliQrOrderRQ)rq; + + AlipayTradePrecreateRequest req = new AlipayTradePrecreateRequest(); + AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + //调起支付宝 (如果异常, 将直接跑出 ChannelException ) + AlipayTradePrecreateResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + + // 构造函数响应数据 + AliQrOrderRS res = ApiResBuilder.buildSuccess(AliQrOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + + if(alipayResp.isSuccess()){ //处理成功 + + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(aliQrOrderRQ.getPayDataType())){ //二维码地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(alipayResp.getQrCode())); + + }else{ //默认都为跳转地址方式 + res.setCodeUrl(alipayResp.getQrCode()); + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }else{ //其他状态, 表示下单失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliWap.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliWap.java new file mode 100644 index 0000000..61a3b6e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/alipay/payway/AliWap.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.channel.alipay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeWapPayModel; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliWapOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliWapOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝 wap支付 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service("alipayPaymentByAliWapService") //Service Name需保持全局唯一性 +public class AliWap extends AlipayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliWapOrderRQ bizRQ = (AliWapOrderRQ)rq; + + AlipayTradeWapPayRequest req = new AlipayTradeWapPayRequest(); + AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + model.setSubject(payOrder.getSubject()); //订单标题 + model.setBody(payOrder.getBody()); //订单描述信息 + model.setTotalAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); //支付金额 + model.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); // 订单超时时间 + model.setProductCode("QUICK_WAP_PAY"); + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setReturnUrl(getReturnUrl()); // 同步跳转地址 + req.setBizModel(model); + + //统一放置 isv接口必传信息 + AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + // 构造函数响应数据 + AliWapOrderRS res = ApiResBuilder.buildSuccess(AliWapOrderRS.class); + + try { + if(CS.PAY_DATA_TYPE.FORM.equals(bizRQ.getPayDataType())){ //表单方式 + res.setFormContent(configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().pageExecute(req).getBody()); + + }else if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + + String payUrl = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().pageExecute(req, "GET").getBody(); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(payUrl)); + }else{ // 默认都为 payUrl方式 + + res.setPayUrl(configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClient().getAlipayClient().pageExecute(req, "GET").getBody()); + } + }catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgPayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgPayKit.java new file mode 100644 index 0000000..9b7489b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgPayKit.java @@ -0,0 +1,477 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.*; + +/** + * 支付通道工具包 + * + * @author xiaoyu + * @date 2022/6/6 11:00 + */ +@Slf4j +public class DgPayKit { + + public static final String STATE_SUCCESS = "00000000"; + public static final String STATE_ING = "00000100"; + public static final String BIZ_SUCCESS = "SUCCESS"; + public static final String STATE_ING_P = "P"; + public static final String STATE_SUCCESS_S = "S"; + public static final String STATE_FAIL_F = "F"; + + public static final String BASE_REQ_URL = "https://api.huifu.com/v2"; + /** + * 企业商户进件请求地址 + **/ + public static final String MCH_APPLY_ENT_URL = "/merchant/basicdata/ent"; + /** + * 个人商户进件请求地址 + **/ + public static final String MCH_APPLY_INDV_URL = "/merchant/basicdata/indv"; + /** + * 商户信息修改 + **/ + public static final String MCH_APPLY_MODIFY_URL = "/merchant/basicdata/modify"; + public static final String MCH_APPLY_UPDATE_URL = "/merchant/integrate/update"; + /** + * 进件状态查询 + **/ + public static final String MCH_APPLY_QUERY_URL = "/merchant/basicdata/status/query"; + /** + * 商户详细信息查询 + **/ + public static final String MCH_INFO_QUERY_URL = "/merchant/basicdata/query"; + /** + * 图片上传 + **/ + public static final String MCH_UPLOAD_PICTURE_URL = "/supplementary/picture"; + /** + * 商户业务开通 + **/ + public static final String MCH_BUSI_OPEN_URL = "/merchant/busi/open"; + /** + * 微信商户配置 + **/ + public static final String MCH_BUSI_CONFIG_URL = "/merchant/busi/config"; + /** + * 结算信息查询 + **/ + public static final String MCH_BUSI_SETTLE_QUERY_URL = "/merchant/basicdata/settlement/query"; + /** + * 智能POS webhook 支付推送事件类型 + **/ + public static List POS_PAY_EVENT = new ArrayList<>(); + + static { + POS_PAY_EVENT.add("pay.union_scaned"); + POS_PAY_EVENT.add("pay.wx_scaned"); + POS_PAY_EVENT.add("pay.ali_scaned"); + POS_PAY_EVENT.add("pay.digit_scaned"); + POS_PAY_EVENT.add("pay.card_consume.pos"); + } + + /** + * 智能POS webhook 退款推送事件类型 + **/ + public static List POS_REFUND_EVENT = new ArrayList<>(); + + static { + POS_REFUND_EVENT.add("refund.card_consume.pos"); + POS_REFUND_EVENT.add("refund.standard"); + } + + /** + * 重写请求方法 + * + * @param reqUrl + * @param bizData + * @return + */ + public static JSONObject req(String reqUrl, DgpayIsvParams isvParams, JSONObject bizData) { + JSONObject reqParams = initReq(isvParams, bizData); + // 生成签名 + TreeMap treeMap = JSON.parseObject(bizData.toJSONString(), TreeMap.class); + JSONObject treeJson = (JSONObject) JSON.toJSON(treeMap); + String sign = sign(treeJson.toJSONString(), isvParams.getRsaPrivateKey()); + reqParams.put("sign", sign); + String requestUrl = BASE_REQ_URL + reqUrl; + log.info("【斗拱】请求地址:{},请求参数:{}", requestUrl, reqParams); + HttpResponse response = post(requestUrl, reqParams.toJSONString()); + log.info("【斗拱】响应结果:{}", response.body()); + return initResult(response.body(), isvParams); + } + + /** + * 处理统一响应结果 + * + * @param result + * @return + */ + private static JSONObject initResult(String result, DgpayIsvParams isvParams) { + JSONObject respData = JSON.parseObject(result); + JSONObject bizData = respData.getJSONObject("data"); + TreeMap signData = JSON.parseObject(JSON.toJSONString(bizData), TreeMap.class); + boolean verifyResult = DgPayKit.verify(JSON.toJSONString(signData), isvParams.getRsaPublicKey(), respData.getString("sign")); + if (!verifyResult) { + throw new BizException("签名校验异常"); + } + if (!DgPayKit.STATE_SUCCESS.equals(bizData.getString("resp_code"))) { + throw new BizException(bizData.getString("resp_desc")); + } + return bizData; + } + + public static JSONObject initReq(DgpayIsvParams isvParams, JSONObject bizData) { + JSONObject reqParams = new JSONObject(); + reqParams.put("sys_id", isvParams.getSysId()); + reqParams.put("product_id", isvParams.getProductId()); + reqParams.put("data", bizData); + return reqParams; + } + + /** + * 放置 请求信息 + **/ + public static JSONObject request(MchAppConfigContext mchAppConfigContext, JSONObject dataParams, String reqUrl, String ifCode) { + // + dataParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + dataParams.put("req_seq_id", DateKit.currentTimeMillis()); + + try { + + JSONObject configParams = getConfigParams(mchAppConfigContext, ifCode); + + JSONObject reqParams = new JSONObject(); + // 请求参数带参 + reqParams.put("sys_id", configParams.getString("sysId")); + reqParams.put("product_id", configParams.getString("productId")); + if (dataParams.getBoolean("noMchId") != null && dataParams.getBoolean("noMchId")) { + } else { + if (StringUtils.isEmpty(dataParams.getString("huifu_id")) && StringUtils.isNotEmpty(configParams.getString("huifuId"))) { + dataParams.put("huifu_id", configParams.getString("huifuId")); + } + } + dataParams.remove("noMchId"); + // 请求数据 + reqParams.put("data", dataParams); + // 生成签名 + TreeMap treeMap = JSON.parseObject(dataParams.toJSONString(), TreeMap.class); + JSONObject treeJson = (JSONObject) JSON.toJSON(treeMap); + String sign = sign(treeJson.toJSONString(), configParams.getString("rsaPrivateKey")); + reqParams.put("sign", sign); + String requestUrl = BASE_REQ_URL + reqUrl; + log.info("【斗拱】请求地址:{},请求参数:{}", requestUrl, reqParams); + HttpResponse response = post(requestUrl, reqParams.toJSONString()); + String res = response.body(); + log.info("【斗拱】响应结果:{}", res); + return JSON.parseObject(res); + } catch (BizException e) { + throw new BizException("[斗拱支付]参数请求异常:" + e.getMessage()); + } + } + + /** + * 支付请求 + **/ + public static JSONObject payRequest(MchAppConfigContext mchAppConfigContext, JSONObject dataParams, String reqUrl, String ifCode) { + JSONObject configParams = getConfigParams(mchAppConfigContext, ifCode); + dataParams.put("channel_no", configParams.getString("channelNo")); + dataParams.put("pay_scene", configParams.getString("payScene")); + JSONObject reqParams = new JSONObject(); + // 请求参数带参 + reqParams.put("sys_id", configParams.getString("sysId")); + reqParams.put("product_id", configParams.getString("productId")); + if (dataParams.getBoolean("noMchId") != null && dataParams.getBoolean("noMchId")) { + } else { + if (StringUtils.isEmpty(dataParams.getString("huifu_id")) && StringUtils.isNotEmpty(configParams.getString("huifuId"))) { + dataParams.put("huifu_id", configParams.getString("huifuId")); + } + } + dataParams.remove("noMchId"); + // 请求数据 + reqParams.put("data", dataParams); + // 生成签名 + TreeMap treeMap = JSON.parseObject(dataParams.toJSONString(), TreeMap.class); + JSONObject treeJson = (JSONObject) JSON.toJSON(treeMap); + String sign = sign(treeJson.toJSONString(), configParams.getString("rsaPrivateKey")); + reqParams.put("sign", sign); + String requestUrl = BASE_REQ_URL + reqUrl; + log.info("【斗拱】请求地址:{},请求参数:{}", requestUrl, reqParams); + HttpResponse response = post(requestUrl, reqParams.toJSONString()); + String res = response.body(); + log.info("【斗拱】响应结果:{}", res); + JSONObject resp = JSON.parseObject(res); + JSONObject data = resp.getJSONObject("data"); + if (!STATE_SUCCESS.equals(data.getString("resp_code")) && !STATE_ING.equals(data.getString("resp_code"))) { + String msg = StringUtils.isNotEmpty(data.getString("bank_message")) ? data.getString("bank_message") : data.getString("resp_desc"); + throw new BizException(msg); + } + return resp; + } + + /** + * 放置 请求信息 + **/ + public static String uploadFile(String isvNo, String fileType, String fileUrl, String ifCode) { + try { + if (StringUtils.isEmpty(fileUrl)) { + return ""; + } + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(new MchApplyment().setIsvNo(isvNo)); + + JSONObject configParams = getConfigParams(mchAppConfigContext, ifCode); + + JSONObject reqParams = new JSONObject(); + // 请求参数带参 + reqParams.put("product_id", configParams.getString("productId")); + reqParams.put("sys_id", configParams.getString("sysId")); + + JSONObject dataParams = new JSONObject(); + dataParams.put("req_seq_id", DateKit.currentTimeMillis()); + dataParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + dataParams.put("file_type", fileType); + dataParams.put("picture", "1.jpg"); + // 请求数据 + reqParams.put("data", dataParams); + // 生成签名 + TreeMap treeMap = JSON.parseObject(dataParams.toJSONString(), TreeMap.class); + JSONObject treeJson = (JSONObject) JSON.toJSON(treeMap); + String sign = sign(treeJson.toJSONString(), configParams.getString("rsaPrivateKey")); + reqParams.put("sign", sign); + String requestUrl = BASE_REQ_URL + MCH_UPLOAD_PICTURE_URL; + log.info("【斗拱】上传图片,请求地址:{},请求参数:{}", requestUrl, reqParams); + + // 下载文件 + byte[] imgFileByteArray = null; + try { + ByteArrayOutputStream baos = ImageUtils.compressNetPic(fileUrl, 2048 * 1024); + imgFileByteArray = baos.toByteArray(); + } catch (IORuntimeException e) { + log.info("斗拱入网压缩图片异常, 图片链接为{}", fileUrl, e); + throw new BizException("银盛入网压缩图片失败, " + e.getMessage()); + } + + @Cleanup HttpResponse response = HttpUtil.createPost(requestUrl) + .form("picture", imgFileByteArray, "1.jpg") + .form("sys_id", configParams.getString("sysId")) + .form("product_id", configParams.getString("productId")) + .form("sign", sign) + .form("data", dataParams.toJSONString()) + .execute(); + String result = response.body(); + log.info("【斗拱】上传图片,响应结果:{}", result); + JSONObject resJson = JSON.parseObject(result); + JSONObject resData = resJson.getJSONObject("data"); + String respCode = resData.getString("resp_code"); + String respDesc = resData.getString("resp_desc"); + if (!DgPayKit.STATE_SUCCESS.equals(respCode)) { + throw new BizException(respDesc); + } + + return resData.getString("file_id"); + } catch (Exception e) { + throw new BizException("[斗拱支付]上传文件请求异常:" + e.getMessage()); + } + } + + /** + * 公共参数 + **/ + public static JSONObject dataParams(PayOrder payOrder, String notifyUrl) { + JSONObject dataParams = new JSONObject(); + // 请求日期 + dataParams.put("req_date", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + dataParams.put("req_seq_id", payOrder.getPayOrderId()); + // 支付金额 元 保留两位小数 + dataParams.put("trans_amt", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 商品描述 + dataParams.put("goods_desc", payOrder.getBody()); + + // 安全信息 + JSONObject riskJson = new JSONObject(); + riskJson.put("ip_addr", payOrder.getClientIp()); + dataParams.put("risk_check_data", riskJson.toJSONString()); + // 订单失效时间 + dataParams.put("time_expire", DateUtil.format(payOrder.getExpiredTime(), DatePattern.PURE_DATETIME_PATTERN)); + // 异步回调地址 + dataParams.put("notify_url", notifyUrl); + return dataParams; + } + + + public static JSONObject getConfigParams(MchAppConfigContext mchAppConfigContext, String ifCode) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + + JSONObject configJson = null; + // 特约商户 + if (mchAppConfigContext.isIsvsubMch()) { + DgpayIsvParams isvParams; + isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + + if (isvParams == null) { + throw new BizException("服务商参数未配置"); + } + + configJson = (JSONObject) JSON.toJSON(isvParams); + + DgpayIsvsubMchParams mchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + if (mchParams != null) { + configJson.put("huifuId", mchAppConfigContext.getMchApplyment().getChannelMchNo()); + configJson.put("payScene", StringUtils.defaultString(mchParams.getPayScene(), "02")); + } + + configJson.put("productId", isvParams.getProductId()); + configJson.put("channelNo", isvParams.getChannelNo()); + } else { + // 普通商户 + DgpayNormalMchParams mchParams = (DgpayNormalMchParams) configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + if (mchParams == null) { + throw new BizException("商户参数未配置"); + } + + configJson = (JSONObject) JSON.toJSON(mchParams); + configJson.put("sysId", mchParams.getHuifuId()); + configJson.put("productId", mchParams.getProductId()); + configJson.put("payScene", StringUtils.defaultString(mchParams.getPayScene(), "02")); + } + return configJson; + } + + /** + * @author: xiaoyu + * @date: 2022/4/13 15:43 + * @describe: 发送请求 + */ + public static HttpResponse post(String url, String params) { + HttpResponse response = HttpUtil.createPost(url) + .header("content-type", "application/json;charset=utf-8") + .timeout(20000) + .charset("utf-8") + .body(params) + .execute(); + return response; + } + + public static String sign(String data, String privateKeyBase64) { + try { + byte[] bytes = Base64.getDecoder().decode(privateKeyBase64); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(keySpec); + Signature signature = Signature.getInstance("SHA256WithRSA"); + signature.initSign(privateKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(signature.sign()); + } catch (Exception var7) { + var7.printStackTrace(); + return null; + } + } + + /** + * RSA公钥验签 + * + * @param data 待签名字符串 + * @param publicKeyBase64 公钥(Base64编码) + * @return 验签结果 + * @throws Exception + */ + public static boolean verify(String data, String publicKeyBase64, String sign) { + // Base64 --> Key + try { + byte[] bytes = Base64.getDecoder().decode(publicKeyBase64); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); + KeyFactory keyFactory; + keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(keySpec); + // verify + Signature signature = Signature.getInstance("SHA256WithRSA"); + signature.initVerify(publicKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + return signature.verify(Base64.getDecoder().decode(sign)); + } catch (Exception e) { + log.error("Exception", e); + return false; + } + + } + + /** + * 转换 + */ + public static String covertChannelId(String channelType) { + return StringUtils.defaultIfBlank(channelType, CS.AUTO_POS_PAY_TYPE.CARD).toLowerCase(); + } + + /** + * 转换 + */ + public static String covertMobilePayType(String payType) { + switch (payType) { + case CS.AUTO_POS_PAY_CHANNEL.ALIPAY: + return "A"; + case CS.AUTO_POS_PAY_CHANNEL.WECHAT: + return "W"; + case CS.AUTO_POS_PAY_CHANNEL.QR_CASHIER: + return "J"; + case CS.AUTO_POS_PAY_CHANNEL.DCEP: + return "D"; + default: + return "U"; + } + } + + /** + * 异常信息返回描述处理 + **/ + public static void channelMsgError(JSONObject resData, ChannelRetMsg channelRetMsg) { + if (StringUtils.isEmpty(resData.getString("bank_message"))) { + + channelRetMsg.setChannelErrMsg(resData.get("resp_desc").toString()); + channelRetMsg.setChannelErrCode(resData.get("resp_code").toString()); + } else { + + channelRetMsg.setChannelErrMsg(resData.getString("bank_message")); + channelRetMsg.setChannelErrCode(resData.get("bank_code").toString()); + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayApplymentApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayApplymentApiService.java new file mode 100644 index 0000000..9bdb051 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayApplymentApiService.java @@ -0,0 +1,301 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IDgApplymentApiService; +import com.jeequan.jeepay.core.model.applyment.DgpayApplymentInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.service.impl.RateConfigService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** + * 斗拱 接口 + * + * @author xiaoyu + * + * @date 2022/6/9 9:25 + */ +@Service +@Slf4j +public class DgpayApplymentApiService implements IDgApplymentApiService { + + @Autowired + protected SysConfigService sysConfigService; + @Autowired + protected RateConfigService rateConfigService; + + @Override + public MchApplyment dgpayConfigOpen(MchApplyment mchApplyment, JSONObject paramJSON) { + String logPrefix = "【斗拱商户分账配置】"; + MchApplyment result = new MchApplyment(); + try { + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB) + .setMchApplyment(mchApplyment); + JSONObject succResJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (succResJson == null || StringUtils.isEmpty(succResJson.getString("huifuId"))) { + result.setApplyErrorInfo("无汇付商户号(huifu_id),请确认是否进件成功"); + return result; + } + + // 最大分账比例 + String applyRatio = paramJSON.getString("applyRatio"); + if (StringUtils.isEmpty(applyRatio)) { + result.setApplyErrorInfo("请填写最大分账比例"); + return result; + } + + // 进件商户号 + String huifuId = succResJson.getString("huifuId"); + + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", huifuId); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + // 分账规则来源 01-接口发起 02-控台配置 + reqParams.put("rule_origin", "01"); + // 分账是否支持撤销交易 + reqParams.put("repeal_flag", "Y"); + // 分账是否支持退货交易 + reqParams.put("refund_flag", "Y"); + // 分账开关 + reqParams.put("div_flag", "Y"); + + // 最大分账比例 未填写分账比例不请求开通分账 + reqParams.put("apply_ratio", applyRatio); + // 生效类型 + reqParams.put("start_type", "0"); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/split/config", mchApplyment.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + log.info("{} 响应结果:resData={}", logPrefix, resData); + + if (!"00000000".equals(resData.getString("resp_code"))) { + result.setApplyErrorInfo(resData.getString("resp_desc")); + } + + result.setChannelVar1(paramJSON.toJSONString()); + + } catch (BizException e) { + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 操作失败:", logPrefix, e); + } catch (Exception e) { + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 操作失败:", logPrefix, e); + } + return result; + } + + @Override + public MchApplyment dgpayConfigOpenQuery(MchApplyment mchApplyment) { + String logPrefix = "【斗拱商户分账配置查询】"; + MchApplyment result = new MchApplyment(); + try { + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + JSONObject succResJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (succResJson == null || StringUtils.isEmpty(succResJson.getString("huifuId"))) { + result.setApplyErrorInfo("无汇付商户号(huifu_id),请确认是否进件成功"); + return result; + } + + // 进件商户号 + String huifuId = succResJson.getString("huifuId"); + + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", huifuId); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + "_" + huifuId); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/split/query", mchApplyment.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + log.info("{} 响应结果:resData={}", logPrefix, resData); + + result.setChannelVar2(resData.toJSONString()); + + } catch (BizException e) { + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 操作失败:", logPrefix, e); + } catch (Exception e) { + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 操作失败:", logPrefix, e); + } + return result; + } + + @Override + public MchApplyment wechatConfigSet(String isvNo, String mchNo, String appId, String jsapiPath, String feeType, String configWxBindLiteAppId, String configWxBindAppId, String bankChannelNo, String ifCode) { + String logPrefix = "【斗拱商户微信配置】"; + MchApplyment result = new MchApplyment(); + try { + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + // 获取支付参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(isvNo, ifCode); + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB).setMchApplyment(new MchApplyment().setIsvNo(isvNo)); + + DgpayIsvsubMchParams mchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchNo, appId, ifCode); + + if (mchParams == null || StringUtils.isEmpty(mchParams.getHuifuId())) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("商户参数未配置,请先配置商户应用参数"); + return result; + } + + // 进件商户号 + String huifuId = mchParams.getHuifuId(); + + // 请求参数 + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", huifuId); + // 产品编号 + reqParams.put("product_id", isvParams.getProductId()); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + + // 业务开通类型 + reqParams.put("fee_type", feeType); + // 授权目录 + reqParams.put("wx_woa_path", jsapiPath); + // 微信小程序APPID + reqParams.put("wx_applet_app_id", configWxBindLiteAppId); + // 公众号APPID + reqParams.put("wx_woa_app_id", configWxBindAppId); + if (StringUtils.isNotEmpty(bankChannelNo)) { + // 渠道号 + reqParams.put("bank_channel_no", bankChannelNo); + } + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, DgPayKit.MCH_BUSI_CONFIG_URL, ifCode); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + if (DgPayKit.STATE_SUCCESS.equals(code)) { + result.setState(MchApplyment.STATE_SUCCESS); + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(code + "[" + resData.getString("resp_desc") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, code, resData.getString("resp_desc")); + return result; + } + } catch (Exception e) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 配置异常:", logPrefix, e); + } + return result; + } + + @Override + public MchApplyment wechatRealName(MchApplyment mchApplyment) { + String logPrefix = "【斗拱商户微信实名认证】"; + MchApplyment result = new MchApplyment(); + try { + // 获取支付参数 + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + JSONObject succResJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (succResJson == null || StringUtils.isEmpty(succResJson.getString("huifuId"))) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("商户参数未配置,请先配置商户应用参数"); + return result; + } + // 进件商户号 + String huifuId = succResJson.getString("huifuId"); + + // 获取详细参数 + DgpayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + + // 请求参数 + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", huifuId); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + + // 联系人姓名 + reqParams.put("name", info.getIdcardName()); + // 联系人手机号 + reqParams.put("mobile", info.getContactPhone()); + // 联系人身份证号 + reqParams.put("id_card_number", info.getIdcardNo()); + + // 法人身份证人像面照片 + reqParams.put("identification_front_copy", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F02", info.getIdcard1Img(), mchApplyment.getIfCode())); + // 法人身份证国徽面照片 + reqParams.put("identification_back_copy", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F03", info.getIdcard2Img(), mchApplyment.getIfCode())); + + // 证书类型 【营业执照】 + reqParams.put("cert_type", "CERTIFICATE_TYPE_2392"); + // 证书编号 + reqParams.put("cert_number", info.getLicenseNo()); + // 证书照片 + reqParams.put("cert_copy", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F07", info.getLicenseImg(), mchApplyment.getIfCode())); + // 小微经营类型 + reqParams.put("micro_biz_type", info.getMicroBizType()); + // 门店名称 + reqParams.put("store_name", info.getMchShortName()); + // 门店门头照 + reqParams.put("store_header_copy", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F49", info.getStoreOuterImg(), mchApplyment.getIfCode())); + // 门店环境照 + reqParams.put("store_indoor_copy", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F50", info.getStoreInnerImg(), mchApplyment.getIfCode())); + // 门店省市编码 + reqParams.put("store_address_code", info.getAreaCode().get(1)); + // 门店地址 + reqParams.put("store_address", info.getMchShortName()); + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/busi/realname", mchApplyment.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + if (DgPayKit.STATE_SUCCESS.equals(code)) { +// String channelOrderNo = resData.getString("applyment_id"); +// result.setChannelApplyNo(channelOrderNo); + result.setState(MchApplyment.STATE_SUCCESS); + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(code + "[" + resData.getString("resp_desc") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, code, resData.getString("resp_desc")); + return result; + } + + } catch (Exception e) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 实名认证失败:", logPrefix, e); + } + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelAccountService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelAccountService.java new file mode 100644 index 0000000..c024a40 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelAccountService.java @@ -0,0 +1,204 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Pair; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.ChannelAccountCashoutRecord; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.cashout.CashoutRetMsg; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelAccountService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** +* 提现接口: 斗拱 +* +* @author zx +* +* @date 2023/6/14 16:19 +*/ +@Slf4j +@Service +public class DgpayChannelAccountService extends AbstractChannelAccountService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public Pair queryBalanceAmount(MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "斗拱商户余额查询"; + + DgpayIsvsubMchParams subMchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + if (subMchParams == null) { + throw new BizException("斗拱商户余额查询,商户参数未配置"); + } + + JSONObject reqParams = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis()); + // 商户号 + reqParams.put("huifu_id", subMchParams.getHuifuId()); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/acctpayment/balance/query", ifCode); + JSONObject jsonData = response.getJSONObject("data"); + + Long balanceAmt = 0L; + // 响应成功 + if (DgPayKit.STATE_SUCCESS.equals(jsonData.getString("resp_code"))) { + // 账户信息列表 + JSONArray infoList = jsonData.getJSONArray("acctInfo_list"); + for (int i = 0; i < infoList.size(); i++) { + JSONObject infoJson = JSONObject.parseObject(infoList.get(i).toString()); + // 查询基本账户类型 + if ("01".equals(infoJson.getString("acct_type"))) { + balanceAmt = Long.parseLong(AmountUtil.convertDollar2Cent(infoJson.getString("balance_amt"))); + } + } + } + + return new Pair<>(subMchParams.getHuifuId(), balanceAmt); + } + + @Override + public CashoutRetMsg cashout(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "斗拱商户提现"; + CashoutRetMsg cashoutRetMsg = new CashoutRetMsg(); + + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + DgpayIsvsubMchParams subMchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + if (subMchParams == null) { + throw new BizException("斗拱商户提现,商户参数未配置"); + } + + try { + if ("0".equals(isvParams.getMchSettManual())) { + throw new BizException("斗拱商户提现,服务商未开启取现配置"); + } + JSONObject reqParams = new JSONObject(); + // 请求流水号 + reqParams.put("req_seq_id", cashoutRecord.getRid()); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 商户号 + reqParams.put("huifu_id", subMchParams.getHuifuId()); + // 到账类型 + reqParams.put("into_acct_date_type", isvParams.getMchSettManual()); + // 取现卡序列号 + reqParams.put("token_no", subMchParams.getTokenNo()); + // 取现金额 + reqParams.put("cash_amt", AmountUtil.convertCent2Dollar(cashoutRecord.getCashoutAmount())); + // 异步通知地址 + reqParams.put("notify_url", getNotifyUrl()); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/settlement/enchashment", ifCode); + JSONObject dataJSON = response.getJSONObject("data"); + + // 响应成功 + if (DgPayKit.STATE_SUCCESS.equals(dataJSON.getString("resp_code"))) { + // 交易状态 S:成功 F:失败 P:处理中 + String transStat = dataJSON.getString("trans_stat"); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + cashoutRetMsg.setChannelOrderId(dataJSON.getString("hf_seq_id")); // 渠道提现单号 + + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrCode(dataJSON.getString("resp_code")); + cashoutRetMsg.setChannelErrMsg(dataJSON.getString("resp_desc")); + + }else { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } + }else { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrMsg(dataJSON.getString("resp_desc")); + } + + return cashoutRetMsg; + + } catch (Exception e) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrMsg(e.getMessage()); + return cashoutRetMsg; + } + + } + + @Override + public CashoutRetMsg cashoutQuery(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "斗拱商户提现结果查询"; + CashoutRetMsg cashoutRetMsg = new CashoutRetMsg(); + + DgpayIsvsubMchParams subMchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + if (subMchParams == null) { + throw new BizException("斗拱商户提现结果查询失败,商户参数未配置"); + } + + try { + JSONObject reqParams = new JSONObject(); + // 商户号 + reqParams.put("huifu_id", subMchParams.getHuifuId()); + // 原交易请求日期 + reqParams.put("org_req_date", DateUtil.format(cashoutRecord.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 原交易请求流水号 + reqParams.put("org_req_seq_id", cashoutRecord.getRid()); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/settlement/query", ifCode); + + JSONObject dataJSON = response.getJSONObject("data"); + + // 响应成功 + if (DgPayKit.STATE_SUCCESS.equals(dataJSON.getString("resp_code"))) { + // 交易状态 S:成功 F:失败 P:处理中 + String transStat = dataJSON.getString("trans_status"); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + cashoutRetMsg.setChannelOrderId(dataJSON.getString("hf_seq_id")); // 渠道提现单号 + + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrCode(dataJSON.getString("resp_code")); + cashoutRetMsg.setChannelErrMsg(dataJSON.getString("resp_desc")); + + }else { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } + }else { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrMsg(dataJSON.getString("resp_desc")); + } + + return cashoutRetMsg; + + } catch (Exception e) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrMsg(e.getMessage()); + return cashoutRetMsg; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelCashoutNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelCashoutNoticeService.java new file mode 100644 index 0000000..1b34f55 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelCashoutNoticeService.java @@ -0,0 +1,146 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.ChannelAccountCashoutRecord; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.cashout.CashoutRetMsg; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelCashoutNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 斗拱提现回调 + * + * @author zx + * + * @date 2023-06-14 07:15 + */ +@Service +@Slf4j +public class DgpayChannelCashoutNoticeService extends AbstractChannelCashoutNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlRid) { + + try { + + // 回调参数body【回调参数顺序固定】 + JSONObject reqParamJSON = getReqParamJSON(); + log.info("【斗拱提现回调参数】{}", reqParamJSON); + JSONObject respData = reqParamJSON.getJSONObject("resp_data"); + String rid = respData.getString("req_seq_id"); + log.info("【斗拱提现回调参数】{}", respData); + return MutablePair.of(rid, reqParamJSON); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public CashoutRetMsg doNotice(HttpServletRequest request, Object params, ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext) { + try { + String logPrefix = "处理斗拱提现回调"; + + CashoutRetMsg cashoutRetMsg = new CashoutRetMsg(); + + JSONObject jsonParams = (JSONObject) params; + log.info("{}参数:{}", logPrefix, jsonParams); + + // 业务失败 + if (!"10000".equals(jsonParams.getString("resp_code"))) { + log.error("{} 业务失败,原因:{}", logPrefix, jsonParams.getString("resp_desc")); + throw ResponseException.buildText("ERROR"); + } + + String respDataStr = jsonParams.getString("resp_data"); + JSONObject respDataJSON = JSONObject.parseObject(respDataStr); + String sign = jsonParams.getString("sign"); + + // 交易状态 S:成功 F:失败 P:处理中 + String transStat = respDataJSON.getString("trans_status"); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + cashoutRetMsg.setChannelOrderId(respDataJSON.getString("hf_seq_id")); // 渠道提现单号 + + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + cashoutRetMsg.setChannelErrCode(respDataJSON.getString("sub_resp_code")); + cashoutRetMsg.setChannelErrMsg(respDataJSON.getString("sub_resp_desc")); + + }else { + cashoutRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } + + // 返回上游内容 + cashoutRetMsg.setResponseEntity(textResp("SUCCESS")); + + // 校验提现回调 + boolean verifyResult = verifyParams(respDataStr, cashoutRecord, mchAppConfigContext, sign); + // 验证参数失败 + if(!verifyResult){ + log.info("{}验证提现通知数据或签名失败", logPrefix); + throw ResponseException.buildText("ERROR"); + } + + cashoutRetMsg.setChannelOrderId(jsonParams.getString("acquireOrderNo")); + cashoutRetMsg.setBankName(jsonParams.getString("bankName")); + cashoutRetMsg.setBankAccount(jsonParams.getString("bankAccount")); + cashoutRetMsg.setBankAccountName(jsonParams.getString("bankAccountName")); + + return cashoutRetMsg; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * 验证斗拱提现通知参数 + * @return + */ + public boolean verifyParams(String respDataStr, ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String sign) { + // 提现金额 + String txnAmt = JSONObject.parseObject(respDataStr).getString("cash_amt"); + if (StringUtils.isEmpty(txnAmt)) { + log.info("金额参数为空 [txnAmt] :{}", txnAmt); + return false; + } + // 核对金额 + long dbPayAmt = cashoutRecord.getCashoutAmount(); + if (dbPayAmt != AmountUtil.convertDollar2CentLong(txnAmt)) { + log.info("订单金额与参数金额不符。 dbPayAmt={}, txnAmt={}, rid={}", dbPayAmt, txnAmt, cashoutRecord.getRid()); + return false; + } + + // 公钥参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), cashoutRecord.getIfCode()); + + // 验证签名 + boolean verifyResult = DgPayKit.verify(respDataStr, isvParams.getRsaPublicKey(), sign); + if(!verifyResult){ + log.info("【斗拱提现回调】 验签失败! 回调参数:respDataStr = {}", respDataStr); + return false; + } + + return true; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelNoticeService.java new file mode 100644 index 0000000..e060d54 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelNoticeService.java @@ -0,0 +1,115 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 斗拱 回调接口实现类 + * + * @author xiaoyu + * + * @date 2022/6/13 15:58 + */ +@Service +@Slf4j +public class DgpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + // 回调参数body【回调参数顺序固定】 + JSONObject reqParamJSON = getReqParamJSON(); + JSONObject dataJson = reqParamJSON.getJSONObject("resp_data"); + String payOrderId = dataJson.getString("req_seq_id"); + return MutablePair.of(payOrderId, reqParamJSON); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + String logPrefix = "【处理[斗拱]支付回调】"; + JSONObject jsonParams = (JSONObject) params; + String dataJson = jsonParams.getString("resp_data"); + String sign = jsonParams.getString("sign"); + log.info("{} 回调参数, dataJson:{}, sign:{}", logPrefix, dataJson, sign); + + // 公钥参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), payOrder.getIfCode()); + + // 验证签名 + boolean verifyResult = DgPayKit.verify(dataJson, isvParams.getRsaPublicKey(), sign); + + //验签失败 + if(!verifyResult){ + throw ResponseException.buildText("ERROR"); + } + + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("SUCCESS"); + + ChannelRetMsg result = new ChannelRetMsg(); + + result.setChannelBizData(jsonParams); + // 默认支付中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 获取请求参数 + JSONObject respData = jsonParams.getJSONObject("resp_data"); + if(DgPayKit.STATE_SUCCESS_S.equals(respData.getString("trans_stat"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if(DgPayKit.STATE_FAIL_F.equals(respData.getString("trans_stat"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + // 交易状态失败存储 + DgPayKit.channelMsgError(respData, result); + } + /*** + * D-借记卡,C-贷记卡,0-其他;示例值:D + */ + String debit_type = respData.getString("debit_type"); + if(StringUtils.isEmpty(debit_type) || "0".equals(debit_type)){ + result.setDrType(CS.DrType.OTHER.getType()); + }else if("D".equals(debit_type)){ + result.setDrType(CS.DrType.DEBIT.getType()); + }else if("C".equals(debit_type)){ + result.setDrType(CS.DrType.CREDIT.getType()); + }else{ + result.setDrType(CS.DrType.OTHER.getType()); + } + result.setResponseEntity(okResponse); + result.setChannelOrderId(respData.getString("hf_seq_id")); + result.setPlatformOrderNo(respData.getString("out_trans_id")); + result.setPlatformMchOrderNo(respData.getString("party_order_id")); + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelOrderAcceptService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelOrderAcceptService.java new file mode 100644 index 0000000..3a515c1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelOrderAcceptService.java @@ -0,0 +1,161 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.ResponseException; +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 com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelOrderAcceptService; +import com.jeequan.jeepay.thirdparty.channel.dgpay.utils.MD5Utils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 斗拱智能POS回调 + * + * @author zx + * + * @date 2021-06-07 07:15 + */ +@Service +@Slf4j +public class DgpayChannelOrderAcceptService extends AbstractChannelOrderAcceptService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public ChannelOrderAcceptParams parseParams(HttpServletRequest request, IsvParams isvParams) { + + JSONObject params = getReqParamJSON(); + + // 获取事件类型 + String eventDefineNo = params.getString("event_define_no"); + + String tradeType = ""; // 交易类型 收款-PAYMENT 退款-REFUND + if (DgPayKit.POS_PAY_EVENT.contains(eventDefineNo)) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_PAYMENT; + } else if (DgPayKit.POS_REFUND_EVENT.contains(eventDefineNo)) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_REFUND; + } + + log.info("斗拱智能POS【订单通知模式】通知参数:tradeType={},params={}", tradeType, params.toJSONString()); + return ChannelOrderAcceptParams.buildAutoPosParams(tradeType, params.getString("devs_id"), params); + } + + @Override + public ChannelOrderAcceptRetMsg payNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) throws Exception { + + String logPrefix = "处理斗拱智能POS【订单通知模式】支付通知"; + + ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg(); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + + // 验签 + boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, request.getParameterMap().get("sign")[0], ifCode); + if(!verifyResult){ + log.info("{}验证通知数据及签名失败", logPrefix); + throw ResponseException.buildText4HttpStatus500("FAIL"); + } + + // 支付状态 + String status = jsonParams.getString("trans_stat"); + // 支付成功 + if (StringUtils.equals(DgPayKit.STATE_SUCCESS_S, status)) { + result.setResponseEntity(textResp("SUCCESS")); // 通知上游处理成功 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + JSONObject transOrderInfo = jsonParams.getJSONObject("trans_order_info"); + result.setChannelOrderId(transOrderInfo.getString("mer_ord_id")); // 渠道订单号,必填 + result.setChannelBizData(JsonKit.newJson("reqSeqId", transOrderInfo.getString("req_seq_id"))); // 分账使用 渠道特殊参数 + + result.setChannelAmount(AmountUtil.convertDollar2CentLong(jsonParams.getString("trans_amt"))); // 订单金额,单位分,必填 + result.setBizOrderId(transOrderInfo.getString("mer_ord_id")); + result.setChannelWayCode(CS.PAY_WAY_CODE.AUTO_POS); // 支付方式,必填 + result.setChannelWayCodeType(covertWayCodeType(jsonParams.getString("event_define_no"))); // 支付方式类型,必填 + result.setChannelDivisionMode(jsonParams.getByte("is_delay_acct")); + + } + return result; + } + + + @Override + public ChannelOrderAcceptRetMsg refundNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) { + try { + String logPrefix = "处理斗拱智能POS【订单通知模式】退款通知"; + + ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg(); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + + // 验签 + boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, request.getParameterMap().get("sign")[0], ifCode); + if(!verifyResult){ + log.info("{}验证通知数据及签名失败", logPrefix); + throw ResponseException.buildText4HttpStatus500("FAIL"); + } + + // 退款状态 + String status = jsonParams.getString("trans_stat"); + // 退款成功 + if (StringUtils.equals(DgPayKit.STATE_SUCCESS_S, status)) { + result.setResponseEntity(textResp("SUCCESS")); // 通知上游处理成功 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + result.setChannelOrderId(jsonParams.getString("mer_ord_id")); // 渠道订单号,必填 + + result.setChannelAmount(AmountUtil.convertDollar2CentLong(jsonParams.getString("ord_amt"))); // 订单金额,单位分,必填 + result.setBizOrderId(jsonParams.getString("mer_ord_id")); + result.setChannelPayOrderId(jsonParams.getString("org_term_ord_id")); // 原渠道订单号(和支付订单渠道订单号一致),退款必填 + result.setChannelDivisionRefundMode((byte) 1); + } + return result; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText4HttpStatus500("FAIL"); + } + } + + /** + * 验签 + * @return + */ + public boolean validateSign(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, String sign, String ifCode) throws Exception { + + DgpayIsvParams isvParams = + (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + + return MD5Utils.verifySign(jsonParams.toJSONString(), isvParams.getWebhookPrivateKey(), sign); + } + + private String covertWayCodeType(String eventDefineNo) { + + switch (eventDefineNo) { + case "pay.ali_scaned": return CS.PAY_WAY_CODE_TYPE.ALIPAY; + case "pay.wx_scaned": return CS.PAY_WAY_CODE_TYPE.WECHAT; + case "pay.union_scaned": + case "pay.card_consume.pos": + case "pay.digit_scaned": + return CS.PAY_WAY_CODE_TYPE.UNIONPAY; + default: return CS.PAY_WAY_CODE_TYPE.OTHER; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelRefundNoticeService.java new file mode 100644 index 0000000..e900bb8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelRefundNoticeService.java @@ -0,0 +1,137 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.util.Map; + +/** + * 斗拱退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class DgpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + // 回调参数body【回调参数顺序固定】 + JSONObject reqParamJSON = getReqParamJSON(); + JSONObject dataJson = reqParamJSON.getJSONObject("resp_data"); + String payOrderId = dataJson.getString("req_seq_id"); + return MutablePair.of(payOrderId, reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + String dataJson = jsonParams.getString("resp_data"); + String sign = jsonParams.getString("sign"); + log.info("【斗拱】退款回调参数:{} ", jsonParams); + // 公钥参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + // 验证签名 + boolean verifyResult = DgPayKit.verify(dataJson, isvParams.getRsaPublicKey(), sign); + //验签失败 + if(!verifyResult){ + throw ResponseException.buildText("ERROR"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("SUCCESS"); + ChannelRetMsg result = new ChannelRetMsg(); + // 默认退款中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 获取请求参数 + JSONObject respData = jsonParams.getJSONObject("resp_data"); + if(DgPayKit.STATE_SUCCESS_S.equals(respData.getString("trans_stat"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if(DgPayKit.STATE_FAIL_F.equals(respData.getString("trans_stat"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + // 交易状态失败存储 + DgPayKit.channelMsgError(respData, result); + } + result.setResponseEntity(okResponse); + result.setChannelOrderId(respData.getString("hf_seq_id")); + result.setPlatformMchOrderNo(respData.getString("party_order_id")); + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证银盛退款通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + log.info("【银盛】退款回调参数: jsonParams:{}", jsonParams); + String sign = jsonParams.getString("sign"); + Map paramsMap = jsonParams.toJavaObject(Map.class); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空:sign:{}", sign); + return false; + } + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + // 证书地址 + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + boolean verifyResult = false; + if ("RSA".equals(isvParams.getSignType())) { + FileInputStream fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile())); + verifyResult = SignRsaUtil.asynVerifyYsRsa(fileInputStream, paramsMap); + }else if ("SM".equals(isvParams.getSignType())){ + verifyResult = SignSmUtil.asynVerifyYsSm(certFilePath, paramsMap); + }else { + log.error("未识别的签名类型"); + } + //验签失败 + if(!verifyResult) { + log.info("【银盛】退款回调验签失败! 回调参数:parameter = {} ", jsonParams); + return false; + } + return true; + }catch (Exception e) { + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelUserService.java new file mode 100644 index 0000000..f3bc229 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayChannelUserService.java @@ -0,0 +1,84 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** +* 获取银联userId实现类 +* +* @author jmdhapy +* +* @date 2022/3/17 16:51 +*/ +@Service +@Slf4j +public class DgpayChannelUserService implements IChannelUserService { + + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("【斗拱】ysfRedirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【斗拱获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); //云闪付 userAuthCode + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + log.info("{} userAuthCode={}, appUpIdentifier={}", logPrefix, userAuthCode, appUpIdentifier); + DgpayIsvsubMchParams mchParams = (DgpayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + + JSONObject reqJson = new JSONObject(); + // 交易流水号 + reqJson.put("req_seq_id", DateKit.currentTimeMillis()+""); + // 请求日期 + reqJson.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 汇付商户号 + reqJson.put("huifu_id", mchParams.getHuifuId()); + // 用户授权码 + reqJson.put("auth_code", userAuthCode); + // 银联支付标识 + reqJson.put("app_up_identifier", appUpIdentifier); + + JSONObject response = DgPayKit.request(mchAppConfigContext, reqJson, "/trade/payment/usermark2/query", ifCode); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + String userId = ""; + if (DgPayKit.STATE_SUCCESS.equals(code)) { + userId = resData.getString("user_id"); + }else { + log.error("请求失败:code={}, sub_msg={}", code, response.getString("resp_desc")); + return userId; + } + return userId; + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayDivisionService.java new file mode 100644 index 0000000..ccf7648 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayDivisionService.java @@ -0,0 +1,477 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.applyment.DgpayApplymentInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * 分账接口 + * + * @author xiaoyu + * + * @date 2022/8/1 15:39 + */ +@Slf4j +@Service +public class DgpayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + @Autowired private DgpayMchApplymentService dgpayMchApplymentService; + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + + try { + + String logPrefix = "[斗拱添加分账]"; + // 新创建的分账接收者的mchId + String newDivisionReceiverSubMchId = null; + + // 实际使用ifCode,用于查询支付参数 + String ifCode = mchDivisionReceiver.getIfCode(); + + // 当channelExtInfo 传入: {} , 说明是subMchId直接绑定模式 + JSONObject channelExtInfoJOSN = JSON.parseObject(mchDivisionReceiver.getChannelExtInfo()); + if(channelExtInfoJOSN.isEmpty()){ + throw new BizException("分账配置信息错误"); + } + newDivisionReceiverSubMchId = mchDivisionReceiver.getAccNo(); + + Boolean isHasAccount = (Boolean) channelExtInfoJOSN.getOrDefault("isHasAccount", false); + + // 新增的分账接收方:调起进件接口,并需要返回一个 subMchId + if(!isHasAccount){ + // 1.基本信息开户 + MchApplyment mchApplyment = new MchApplyment(); // 构造进件相关请求参数 + mchApplyment.setApplyId(SeqKit.genMchApplyNo()); + mchApplyment.setIsvNo(mchAppConfigContext.getMchApplyment().getIsvNo()); + mchApplyment.setApplyDetailInfo(mchDivisionReceiver.getChannelExtInfo()); + mchApplyment.setIfCode(ifCode); + // 进件参数 + JSONObject reqParams = dgpayMchApplymentService.getApplymentParams(mchApplyment); + // 开户参数 + dgpayMchApplymentService.setAccountInfo(mchApplyment, reqParams); + + // 银行卡参数 + JSONObject cardInfo = reqParams.getJSONObject("card_info"); + reqParams.remove("card_info"); + + DgpayApplymentInfo applymentInfo = JSONObject.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + + JSONArray fileArr = new JSONArray(); + // 门头照 + String storeOuterImg = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F49", applymentInfo.getStoreOuterImg(), ifCode); + if (StringUtils.isNotEmpty(storeOuterImg)) { + JSONObject json = JsonKit.newJson("file_type", "F49"); + json.put("file_id", storeOuterImg); + fileArr.add(json); + } + // 内景照 + String storeInnerImg = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F50", applymentInfo.getStoreInnerImg(), ifCode); + if (StringUtils.isNotEmpty(storeInnerImg)) { + JSONObject json = JsonKit.newJson("file_type", "F50"); + json.put("file_id", storeInnerImg); + fileArr.add(json); + } + // 收银台照 + String storeCashierImg = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F105", applymentInfo.getStoreCashierImg(), ifCode); + if (StringUtils.isNotEmpty(storeCashierImg)) { + JSONObject json = JsonKit.newJson("file_type", "F105"); + json.put("file_id", storeCashierImg); + fileArr.add(json); + } + // 法人身份证人像面照片 + String idcard1Img = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F02", applymentInfo.getIdcard1Img(), ifCode); + if (StringUtils.isNotEmpty(idcard1Img)) { + JSONObject json = JsonKit.newJson("file_type", "F02"); + json.put("file_id", idcard1Img); + fileArr.add(json); + } + // 法人身份证国徽面照片 + String idcard2Img = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F03", applymentInfo.getIdcard2Img(), ifCode); + if (StringUtils.isNotEmpty(idcard2Img)) { + JSONObject json = JsonKit.newJson("file_type", "F03"); + json.put("file_id", idcard2Img); + fileArr.add(json); + } + // 营业执照 + String licenseImg = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F07", applymentInfo.getLicenseImg(), ifCode); + if (StringUtils.isNotEmpty(licenseImg)) { + JSONObject json = JsonKit.newJson("file_type", "F07"); + json.put("file_id", licenseImg); + fileArr.add(json); + } + // 商务协议 + String baPicImg = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F116", applymentInfo.getBankPic(), ifCode); + if (StringUtils.isNotEmpty(baPicImg)) { + JSONObject json = JsonKit.newJson("file_type", "F116"); + json.put("file_id", baPicImg); + fileArr.add(json); + } + + reqParams.put("file_list", fileArr.toJSONString()); + + // 步骤1 请求地址 企业开户和个人开户地址 + String step1Url = applymentInfo.getMerchantType() == 1?"/user/basicdata/indv":"/user/basicdata/ent"; + // 发起开户请求 + JSONObject responseStep1 = DgPayKit.request(mchAppConfigContext, reqParams, step1Url, ifCode); + JSONObject dataJson1 = responseStep1.getJSONObject("data"); + // 响应失败 + if (!DgPayKit.STATE_SUCCESS.equals(dataJson1.getString("resp_code"))) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(dataJson1.getString("resp_code")); + channelRetMsg.setChannelErrMsg(dataJson1.getString("resp_desc")); + return channelRetMsg; + } + // 获取汇付ID号 + String huifuId = dataJson1.getString("huifu_id"); + + // 2.业务入驻 + DgpayIsvsubMchParams mchParams = (DgpayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), ifCode); + // 汇付ID + reqParams.put("huifu_id", huifuId); + // 请求流水号 + reqParams.put("req_seq_id", SeqKit.genMchApplyNo()); + // 商户编号 + reqParams.put("upper_huifu_id", mchParams.getHuifuId()); + // 延迟入账开关 + reqParams.put("delay_flag", "Y"); + // 银行卡参数 + reqParams.put("card_info", cardInfo); + reqParams.remove("noMchId"); + // 步骤2 请求地址 用户业务入驻 + String step2Url = "/user/busi/open"; + // 发起开户请求 + JSONObject responseStep2 = DgPayKit.request(mchAppConfigContext, reqParams, step2Url, ifCode); + JSONObject dataJson2 = responseStep2.getJSONObject("data"); + // 响应失败 + if (!DgPayKit.STATE_SUCCESS.equals(dataJson2.getString("resp_code"))) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + // 状态失败 + DgPayKit.channelMsgError(dataJson2, channelRetMsg); + return channelRetMsg; + } + JSONObject paramsJson = new JSONObject(); + String tokenNo = dataJson2.getString("token_no"); + paramsJson.put("tokenNo", tokenNo); + paramsJson.put("huifuId", huifuId); + newDivisionReceiverSubMchId = paramsJson.toJSONString(); + }else { + JSONObject paramsJson = JsonKit.newJson("huifuId", newDivisionReceiverSubMchId); + // 取现卡序列号 + if (StringUtils.isNotEmpty(mchDivisionReceiver.getChannelExtInfo())) { + String tokenNo = channelExtInfoJOSN.getString("tokenNo"); + paramsJson.put("tokenNo", tokenNo); + } + + newDivisionReceiverSubMchId = paramsJson.toJSONString(); + } + + //在channelAttach数据中,写入 渠道用户编号 + return ChannelRetMsg.confirmSuccess(null).setChannelAttach(newDivisionReceiverSubMchId); + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("添加斗拱分账异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + + try { + // 分账批次号 + String batchOrderId = recordList.get(0).getBatchOrderId(); + + if(recordList.isEmpty()){ // 当无分账用户时,直接响应成功即可。 + return ChannelRetMsg.confirmSuccess(null); + } + + String logPrefix = "【斗拱分账】"; + + DgpayIsvsubMchParams isvsubMchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrder.getIfCode()); + String mchId = isvsubMchParams.getHuifuId(); + + JSONObject reqParams = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", batchOrderId); + // 商户号 + reqParams.put("huifu_id", mchId); + + String orgReqSeqId = payOrder.getPayOrderId(); + if (StringUtils.equals(CS.PAY_WAY_CODE.AUTO_POS, payOrder.getWayCode())) { + orgReqSeqId = payOrder.getChannelOrderNo(); + + if (payOrder.getChannelBizData() != null && StringUtils.isNotBlank(payOrder.getChannelBizData())) { + JSONObject channelBizData = JSONObject.parseObject(payOrder.getChannelBizData()); + + if (StringUtils.isNotBlank(channelBizData.getString("reqSeqId"))) { + orgReqSeqId = channelBizData.getString("reqSeqId"); + } + } + } + // 原交易请求流水号 + reqParams.put("org_req_seq_id", orgReqSeqId); + // 下单日期 + reqParams.put("org_req_date", DateUtil.format(payOrder.getSuccessTime(), DatePattern.PURE_DATE_PATTERN)); + + JSONArray receivers = new JSONArray(); + for (int i = 0; i < recordList.size(); i++) { + PayOrderDivisionRecord record = recordList.get(i); + if(record.getCalDivisionAmount() <= 0){ //金额为 0 不参与分账处理 + continue; + } + if(StringUtils.isEmpty(record.getChannelAccNo())){ // 判断是否都包含渠道号码 + throw new BizException(record.getAccName() + "账号没有分账渠道号, 本次分账失败"); + } + + JSONObject paramsJson = JSONObject.parseObject(record.getChannelAccNo()); + JSONObject receiver = new JSONObject(); + receiver.put("huifu_id", paramsJson.getString("huifuId")); + receiver.put("div_amt", AmountUtil.convertCent2Dollar(record.getCalDivisionAmount())); + receivers.add(receiver); + } + + if(receivers.isEmpty()){ + return ChannelRetMsg.confirmSuccess(null); + } + + // 分账对象 + JSONObject receiverJson = new JSONObject(); + receiverJson.put("acct_infos", receivers); + reqParams.put("acct_split_bunch", receiverJson.toJSONString()); + + log.info("{}分账处理分账接收方", logPrefix); + // 发起分账请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/delaytrans/confirm", payOrder.getIfCode()); + JSONObject dataJson = response.getJSONObject("data"); + // 响应失败 + if (!DgPayKit.STATE_SUCCESS.equals(dataJson.getString("resp_code"))) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + // 状态失败 + DgPayKit.channelMsgError(dataJson, channelRetMsg); + return channelRetMsg; + } + + // 业务处理成功, 响应成功 交易状态为成功 + if(DgPayKit.STATE_SUCCESS.equals(dataJson.getString("resp_code")) && "S".equals(dataJson.getString("trans_stat"))) { + + return ChannelRetMsg.confirmSuccess(dataJson.getString("req_seq_id")); + } + + // 订单处理中: 需要延迟到第二天5点进行结算 + if("P".equals(dataJson.getString("trans_stat"))){ + + // 第二天的5点钟 + Date nextDay5 = DateUtil.offset(DateKit.getBegin(DateUtil.offsetDay(new Date(), 1)), DateField.HOUR, 5); + + // 触发MQ的时间, 单位: 秒 + Long delayTime = (nextDay5.getTime() - DateKit.currentTimeMillis()) / 1000; + + return ChannelRetMsg.unknown().setChannelAttach(JsonKit.newJson("mqDelayTime", delayTime).toJSONString()); + + }else{ //其他情况认为: 失败 + return ChannelRetMsg.confirmFail().setChannelErrCode(dataJson.getString("resp_code")).setChannelErrMsg(dataJson.getString("resp_desc")); + } + + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("斗拱分账异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "【斗拱分账回退】"; + + try { + // 防止接口限流 + Thread.sleep(1000); + + DgpayIsvsubMchParams isvsubMchParams = (DgpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrderDivisionRecord.getIfCode()); + + JSONObject reqParams = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", payOrderDivisionRefundRecord.getDivisionRefundId()); + // 商户号 + reqParams.put("huifu_id", isvsubMchParams.getHuifuId()); + // 原交易请求日期 + reqParams.put("org_req_date", DateUtil.format(payOrderDivisionRecord.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 原交易请求流水号 + reqParams.put("org_req_seq_id", payOrderDivisionRecord.getChannelBatchOrderId()); + JSONObject paramsJson = JSONObject.parseObject(payOrderDivisionRecord.getChannelAccNo()); + JSONArray refundArr = new JSONArray(); + JSONObject refundJson = new JSONObject(); + refundJson.put("huifu_id", paramsJson.getString("huifuId")); + refundJson.put("div_amt", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount())); + refundArr.add(refundJson); + + JSONObject receiverJson = new JSONObject(); + receiverJson.put("acct_infos", refundArr); + reqParams.put("acct_split_bunch", receiverJson.toJSONString()); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/delaytrans/confirmrefund", payOrderDivisionRecord.getIfCode()); + JSONObject jsonData = response.getJSONObject("data"); + // 响应失败 + if (!DgPayKit.STATE_SUCCESS.equals(jsonData.getString("resp_code"))) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + // 状态失败 + DgPayKit.channelMsgError(jsonData, channelRetMsg); + return channelRetMsg; + } + return ChannelRetMsg.confirmSuccess(jsonData.getString("hf_seq_id")); + + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "【斗拱分账余额查询】"; + try { + JSONObject paramsJson = JSONObject.parseObject(mchDivisionReceiver.getChannelAccNo()); + + JSONObject reqParams = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis()); + // 商户号 + reqParams.put("huifu_id", paramsJson.getString("huifuId")); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/acctpayment/balance/query", mchDivisionReceiver.getIfCode()); + JSONObject jsonData = response.getJSONObject("data"); + + Long balanceAmt = 0L; + // 响应成功 + if (DgPayKit.STATE_SUCCESS.equals(jsonData.getString("resp_code"))) { + // 账户信息列表 + JSONArray infoList = jsonData.getJSONArray("acctInfo_list"); + for (int i = 0; i < infoList.size(); i++) { + JSONObject infoJson = JSONObject.parseObject(infoList.get(i).toString()); + // 查询基本账户类型 + if ("01".equals(infoJson.getString("acct_type"))) { + balanceAmt = Long.parseLong(AmountUtil.convertDollar2Cent(infoJson.getString("balance_amt"))); + } + } + } + return balanceAmt; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "斗拱分账账号提现"; + try { + Long thisBalanceAmount = queryBalanceAmount(mchDivisionReceiver, mchAppConfigContext); + if(thisBalanceAmount < amount){ + throw new BizException("商户可用余额不足"); + } + JSONObject paramsJson = JSONObject.parseObject(mchDivisionReceiver.getChannelAccNo()); + + JSONObject reqParams = new JSONObject(); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis()); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 商户号 + reqParams.put("huifu_id", paramsJson.getString("huifuId")); + + // 取现卡序列号 + String tokenNo = paramsJson.getString("tokenNo"); + + if (StringUtils.isEmpty(tokenNo)) { + throw new BizException("取现卡序列号不能为空"); + } + + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() +"_"+ 1); + // 到账类型 + reqParams.put("into_acct_date_type", "T0"); + // 取现卡序列号 + reqParams.put("token_no", tokenNo); + // 取现金额 + reqParams.put("cash_amt", AmountUtil.convertCent2Dollar(amount)); + + log.info(logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/settlement/enchashment", mchDivisionReceiver.getIfCode()); + JSONObject jsonData = response.getJSONObject("data"); + + // 响应成功 + if (DgPayKit.STATE_SUCCESS.equals(jsonData.getString("resp_code"))) { + // 交易状态 + String transStat = jsonData.getString("trans_stat"); + if (DgPayKit.STATE_ING_P.equals(transStat)) { + String channelNo = jsonData.getString("hf_seq_id"); + return ChannelRetMsg.confirmSuccess(channelNo); + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + return ChannelRetMsg.confirmFail(jsonData.getString("resp_code"), jsonData.getString("resp_desc")); + } + } + return ChannelRetMsg.waiting(); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..9ef2dd8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchAlipayConfigService.java @@ -0,0 +1,322 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.DgpayApplymentInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.Objects; + +@Service +@Slf4j +public class DgpayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + private void realNameApply(MchApplyment mchApplyment, DgpayIsvParams isvParams) { + DgpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", suJson.getString("huifuId")); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + + reqParams.put("pay_scene", "1"); + + // 主体信息 + JSONObject authIdentityInfo = new JSONObject(); + reqParams.put("auth_identity_info", authIdentityInfo); + authIdentityInfo.put("business_type", getBusinessType(mchApplyment.getMerchantType())); + authIdentityInfo.put("finance_institution_flag", "N"); + + if (mchApplyment.getMerchantType() == MchApplyment.MERCHANT_TYPE_PERSONAL) { + JSONObject supportCredentials = new JSONObject(); + authIdentityInfo.put("support_credentials", supportCredentials); + supportCredentials.put("micro_biz_type", applymentInfo.getMicroBizType()); + supportCredentials.put("store_name", applymentInfo.getMchShortName()); + supportCredentials.put("province_code", applymentInfo.getAreaCode().getString(0)); + if (applymentInfo.getAreaName() != null) { + supportCredentials.put("province", applymentInfo.getAreaName().getString(0)); + } + supportCredentials.put("city_code", applymentInfo.getAreaCode().getString(1)); + if (applymentInfo.getAreaName() != null) { + supportCredentials.put("city", applymentInfo.getAreaName().getString(1)); + } + supportCredentials.put("district_code", applymentInfo.getAreaCode().getString(2)); + if (applymentInfo.getAreaName() != null) { + supportCredentials.put("district", applymentInfo.getAreaName().getString(2)); + } + + if (applymentInfo.getMicroBizType().equals("MICRO_TYPE_MOBILE")) { + supportCredentials.put("store_address", "无"); + } else { + supportCredentials.put("store_address", applymentInfo.getAddress()); + } + + String f49 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F49", applymentInfo.getStoreOuterImg(), mchApplyment.getIfCode()); + supportCredentials.put("store_door_img", f49); + + String f50 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F50", applymentInfo.getStoreInnerImg(), mchApplyment.getIfCode()); + supportCredentials.put("store_inner_img", f50); + } else { + authIdentityInfo.put("certificate_type", "BUSINESS_CERT"); + + JSONObject certificateInfo = new JSONObject(); + authIdentityInfo.put("certificate_info", certificateInfo); + certificateInfo.put("cert_number", applymentInfo.getLicenseNo()); + String f07 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F07", applymentInfo.getLicenseImg(), mchApplyment.getIfCode()); + certificateInfo.put("cert_copy", f07); + certificateInfo.put("cert_merchant_name", applymentInfo.getMchFullName()); + certificateInfo.put("cert_legal_person", applymentInfo.getIdcardName()); + certificateInfo.put("cert_company_address", applymentInfo.getLicenseAddress()); + certificateInfo.put("effect_time", applymentInfo.getLicenseEffectBegin().replace("-", "")); + certificateInfo.put("expire_time", applymentInfo.getLicenseEffectEnd().replace("-", "")); + } + + JSONObject contactPersonInfo = new JSONObject(); + reqParams.put("contact_person_info", contactPersonInfo); + contactPersonInfo.put("id_card_number", applymentInfo.getContactIdcardNo()); + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/busi/ali/realname/apply", mchApplyment.getIfCode()) + .getJSONObject("data"); + + if (!DgPayKit.STATE_SUCCESS.equals(response.getString("resp_code"))) { + throw new BizException(response.getString("resp_desc")); + } + + String applymentId = response.getString("applyment_id"); + String orderStatus = response.getString("order_status"); + + if (orderStatus.equals("AUDITING")) { + suJson.put("zfb_applyment_id", applymentId); + } + mchApplyment.setSuccResParameter(suJson.toJSONString()); + mchApplymentService.updateById(mchInfoConverter.toDbEntity(mchApplyment)); + } + + private String getBusinessType(Byte merchantType) { + if (merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL) { + return "0"; + } + + if (merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL) { + return "5"; + } + + if (merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE) { + return "3"; + } + + throw new BizException("无法判定的其他主体类型"); + } + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + + // 服务商配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode()); + + ApplymentSignInfo result = new ApplymentSignInfo(); + + // 进件商户信息 + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (suJson == null || StringUtils.isEmpty(suJson.getString("huifuId"))) { + result.setState("查询失败"); + result.setErrInfo("商户参数为空,该商户还未进件成功"); + return result; + } + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", suJson.getString("huifuId")); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/busi/realname/query", mchApplyment.getIfCode()) + .getJSONObject("data"); + + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + "_info"); + // 商户详情is_open_small_flag -> 0 + JSONObject mchInfo = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/basicdata/query", mchApplyment.getIfCode()); + JSONObject mchInfoData = mchInfo.getJSONObject("data"); + String feeConfig = ""; + JSONArray wxConfList = mchInfoData.getJSONArray("qry_wx_conf_list"); + JSONArray aliConfList = mchInfoData.getJSONArray("qry_ali_conf_list"); + JSONObject unionConf = mchInfoData.getJSONObject("qry_union_conf"); + JSONObject bankCardConf = mchInfoData.getJSONObject("qry_bank_card_conf"); + + for (int aliIndex = 0; aliIndex < aliConfList.size(); aliIndex++) { + JSONArray aliMerInfos = aliConfList.getJSONObject(aliIndex).getJSONArray("ali_mer_infos"); + + if (!CollUtil.isEmpty(aliMerInfos)) { + + for (int i = 0; i < aliMerInfos.size(); i++) { + JSONObject item = aliMerInfos.getJSONObject(i); + // 支付宝子商户号存在时 + MchSubInfoEntity zfbSubInfo = new MchSubInfoEntity(); + zfbSubInfo.setMchApplyId(mchApplyment.getApplyId()); + + String payChannelId = item.getString("pay_channel_id"); + String bankMerCode = item.getString("bank_mer_code"); + if (Objects.equals(isvParams.getChannelNo(), payChannelId)) { + zfbSubInfo.setMainUse(1); + result.setChannelSubMchId(bankMerCode); + } else { + zfbSubInfo.setMainUse(0); + } + zfbSubInfo.setSubMchWay("DG"); + zfbSubInfo.setChannelMchNo(mchApplyment.getChannelMchNo()); + zfbSubInfo.setChannelId(payChannelId); + zfbSubInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + zfbSubInfo.setSubMchId(bankMerCode); + zfbSubInfo.setSubMchType("ZFB"); + // 此处取1为正常 + zfbSubInfo.setStatus("1"); + zfbSubInfo.setExt(item); + + try { + mchSubInfoService.save(zfbSubInfo); + } catch (DuplicateKeyException e) { + log.info("子商户信息已存储过"); + } + } + } + } + + + // 支付宝申请单编号 +// String applymentId = suJson.getString("zfb_applyment_id"); +// if (applymentId == null) { +// realNameApply(mchApplyment, isvParams); +// } + + reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", suJson.getString("huifuId")); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); +// reqParams.put("pay_channel_id", DateKit.currentTimeMillis()+""); +// reqParams.put("pay_scene", "1"); + + // 发送请求 + JSONObject response2 = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/busi/ali/realname/query", mchApplyment.getIfCode()) + .getJSONObject("data"); + + String respCode = response2.getString("resp_code"); + String respDesc = response2.getString("resp_desc"); + + if (!respCode.equals("00000000")) { + result.setState("获取子商户状态异常"); + result.setErrInfo("【" + respDesc + "】"); + result.setImgType("qrContent"); + result.setSignUrl(isvParams.getAliChannelExtUrl()); + return result; + } + + String orderStatus = response2.getString("order_status"); + if ("AUDITING".equals(orderStatus)) { + result.setState("审核中"); + } else if ("CONTACT_CONFIRM".equals(orderStatus)) { + result.setState("待联系人确认(扫码确认授权)"); + result.setImgType("imgUrl"); + result.setSignUrl(response2.getString("qrcode")); + } else if ("LEGAL_CONFIRM".equals(orderStatus)) { + result.setState("待法人确认(扫码确认授权)"); + result.setImgType("imgUrl"); + result.setSignUrl(response2.getString("qrcode")); + } else if ("AUDIT_PASS".equals(orderStatus)) { + result.setState("审核通过"); + } else if ("AUDIT_REJECT".equals(orderStatus)) { + result.setState("审核失败"); + } else if ("AUDIT_FREEZE".equals(orderStatus)) { + result.setState("已冻结(扫码确认授权)"); + result.setImgType("imgUrl"); + result.setSignUrl(response2.getString("qrcode")); + } else if ("CANCELED".equals(orderStatus)) { + result.setState("已撤回"); + } else if ("NOT_APPLY".equals(orderStatus)) { + result.setState("未申请"); + } + + String authorizeStat = response2.getString("authorize_stat"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + + if ("AUTHORIZED".equals(authorizeStat)) { + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + result.setState("已授权"); + } else if ("UNAUTHORIZED".equals(authorizeStat)) { + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + result.setState("未授权"); + } else if ("CLOSED".equals(authorizeStat)) { + result.setState("已销户"); + } else { + result.setState("未报备"); + } + + + if (ObjUtil.isEmpty(result.getSignUrl())) { + // 渠道拓展地址 + result.setImgType("qrContent"); + result.setSignUrl(isvParams.getAliChannelExtUrl()); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..0134e83 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchApplymentNotifyService.java @@ -0,0 +1,205 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.text.CharSequenceUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +@Slf4j +@Service +public class DgpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + + JSONObject data = reqParamJSON.getJSONObject("data"); + + String applyNo = data.getString("apply_no"); + + com.jeequan.jeepay.db.entity.MchApplyment mchApplyment = mchApplymentService.getByOrderId(applyNo); + if (mchApplyment == null) { + // 此时查询变更的申请单 + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(applyNo, CS.IF_CODE.DGPAY); + if (mchModifyApplyment == null) { + return MutablePair.of(null, data); + } + mchApplyment = mchApplymentService.getByChannelMchNo(mchModifyApplyment.getChannelMchNo()); + } + + if (mchApplyment == null) { + return MutablePair.of(null, data); + } + + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchInfoConverter.toModel(mchApplyment)); + + + boolean verify = DgPayKit.verify(data.toJSONString(), isvParams.getRsaPublicKey(), reqParamJSON.getString("sign")); + if (!verify) { + log.info("斗拱支付回调参数验签不通过"); + } + + return MutablePair.of(mchApplyment.getApplyId(), data); + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment) { + + JSONObject response = ((JSONObject) params); + + JSONObject resData = response.getJSONObject("data"); + String notifyType = resData.getString("notify_type"); + + if (response.getString("apply_no").equals(mchApplyment.getChannelApplyNo())) { + // 入网回调 + if (CharSequenceUtil.isEmpty(notifyType)) { + applyResult(resData, mchApplyment); + } else { + // 报备回调 + reportResult(resData, mchApplyment); + + return MutablePair.of(mchApplyment, retOk("RECV_ORD_ID_" + resData.getString("ord_id"))); + } + } else { + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(response.getString("apply_no"), CS.IF_CODE.DGPAY); + // 变更回调 + changeResult(resData, mchInfoConverter.toModel(mchModifyApplyment)); + } + + return MutablePair.of(mchApplyment, retOk(null)); + } + + private void changeResult(JSONObject resData, MchModifyApplyment modifyApplyment) { + String auditStatus = resData.getString("audit_status"); + String auditDesc = resData.getString("audit_desc"); + + MchModifyApplymentEntity result = new MchModifyApplymentEntity(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + if ("Y".equals(auditStatus)) { + // 变更成功 + modifyApplymentService.localModify(modifyApplyment); + } else if ("N".equals(auditStatus) || "F".equals(auditStatus)) { + // 变更失败 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + auditDesc + "]"); + + modifyApplymentService.updateById(result); + } + } + + private void reportResult(JSONObject resData, MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + String code = resData.getString("sub_resp_code"); + String notifyType = resData.getString("notify_type"); + String huifuId = resData.getString("huifu_id"); + + if (!"00000000".equals(code)) { + return; + } + + MchSubInfo mchSubInfo = new MchSubInfo(); + mchSubInfo.setChannelMchNo(huifuId); + mchSubInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + switch (notifyType) { + case "W": + mchSubInfo.setSubMchType("WX"); + break; + case "A": + mchSubInfo.setSubMchType("ZFB"); + break; + case "U": + mchSubInfo.setSubMchType("BANK"); + break; + default: + } + // 通知类型,没有则是申请单审核异步回调 + + JSONArray regResultList = resData.getJSONArray("reg_result_list"); + + if (regResultList == null || regResultList.isEmpty()) { + return; + } + + for (int i = 0; i < regResultList.size(); i++) { + JSONObject item = regResultList.getJSONObject(i); + + MchSubInfo newEntity = mchInfoConverter.clone(mchSubInfo); + newEntity.setExt(item); + newEntity.setStatus(item.getString("business_stat")); + newEntity.setSubMchId(item.getString("sub_mer_id")); + newEntity.setChannelId(item.getString("pay_channel_id")); + mchSubInfoService.save(mchInfoConverter.toDbEntity(newEntity)); + } + } + + private void applyResult(JSONObject resData, MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + String code = resData.getString("sub_resp_code"); + + if ("00000000".equals(code)) { + return; + } + + String auditStatus = resData.getString("audit_status"); + String auditDesc = resData.getString("audit_desc"); + // 通知类型,没有则是申请单审核异步回调 + + if ("Y".equals(auditStatus)) { + String huifuId = resData.getString("huifu_id"); + // 进件查询响应参数 + result.setApplyErrorInfo("[" + auditDesc + "]"); + result.setState(MchApplyment.STATE_SUCCESS); + result.setChannelMchNo(huifuId); + result.setSuccResParameter(resData.toString()); + mchApplymentService.updateById(mchInfoConverter.toDbEntity(result)); + } else if ("N".equals(auditStatus) || "F".equals(auditStatus)) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + auditDesc + "]"); + mchApplymentService.updateById(mchInfoConverter.toDbEntity(result)); + } + } + + @Override + public ResponseEntity retOk(Object params) { + return ResponseEntity.ok("SUCCESS"); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..e822c28 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchModifyApplymentService.java @@ -0,0 +1,634 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.DgpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; + +@Slf4j +@Service +public class DgpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + DgpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, DgpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + DgpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, DgpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + if ("Y".equals(mchModifyData.getIllegal())) { + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + } + + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setAuthEnturstPic(mchModifyData.getNonLegSettleAuthPic()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + DgpayIsvParams isvParams = ((DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + Date today = new Date(); + String formatDate = DateUtil.format(today, DatePattern.PURE_DATE_PATTERN); + param.put("req_seq_id", formatDate + mchModifyApplyment.getApplyId()); + param.put("req_date", formatDate); + param.put("upper_huifu_id", isvParams.getSysId()); + param.put("huifu_id", mchApplyment.getChannelMchNo()); + param.put("short_name", mchModifyData.getMchShortName()); + param.put("async_return_url", getCallbackUrl(mchApplyment.getIfCode())); + + JSONObject agreementInfo = new JSONObject(); + agreementInfo.put("agreement_type", "0"); + param.put("agreement_info", agreementInfo.toJSONString()); + + JSONObject signUserInfo = new JSONObject(); + param.put("sign_user_info", signUserInfo); + + DgpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + switch (applymentInfo.getSettAccountType()) { + case "B": + case "C": + // 对公 + signUserInfo.put("type", "LEGAL"); + signUserInfo.put("mobile_no", applymentInfo.getIdCardPhone()); + break; + case "D": + signUserInfo.put("type", "OTHER"); + signUserInfo.put("name", applymentInfo.getSettAccountName()); + signUserInfo.put("mobile_no", applymentInfo.getSettAccountBindPhone()); + signUserInfo.put("cert_no", applymentInfo.getSettAccountIdcardNo()); + break; + } + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + try { + JSONObject applyResp = DgPayKit.request(mchAppConfigContext, param, DgPayKit.MCH_APPLY_MODIFY_URL, mchApplyment.getIfCode()); + JSONObject applyRespData = applyResp.getJSONObject("data"); + String code = applyRespData.getString("sub_resp_code"); + String msg = applyRespData.getString("sub_resp_desc"); + + if ("00000000".equals(code)) { + // 请求成功 + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + return localModifyBase(new MutablePair<>(resultModifyApplyment, mchDataPair.right)); + } else if ("90000000".equals(code)) { + // 审核中 + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + // 其他暂定为失败 + resultModifyApplyment.setApplyErrorInfo("[" + msg + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + + String remark = "斗拱支付基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("斗拱支付基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + DgpayIsvParams isvParams = ((DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + Date today = new Date(); + String formatDate = DateUtil.format(today, DatePattern.PURE_DATE_PATTERN); + param.put("req_seq_id", formatDate + mchModifyApplyment.getApplyId()); + param.put("req_date", formatDate); + param.put("upper_huifu_id", isvParams.getSysId()); + param.put("huifu_id", mchApplyment.getChannelMchNo()); + + param.put("async_return_url", getCallbackUrl(mchApplyment.getIfCode())); + + JSONObject cardInfo = new JSONObject(); + + if ("B".equals(mchModifyData.getSettAccountType())) { + String f13 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F13", mchModifyData.getSettAccountLicenseImg(), mchApplyment.getIfCode()); + cardInfo.put("settle_card_front_pic", f13); + } else { + String f08 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F08", mchModifyData.getChangeFormPic(), mchApplyment.getIfCode()); + cardInfo.put("reg_acct_pic", f08); + } + String f55 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F55", mchModifyData.getSettAccountIdcard1Img(), mchApplyment.getIfCode()); + cardInfo.put("settle_cert_front_pic", f55); + String f56 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F56", mchModifyData.getSettAccountIdcard2Img(), mchApplyment.getIfCode()); + cardInfo.put("settle_cert_back_pic", f56); + String f15 = DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F15", mchModifyData.getNonLegSettleAuthPic(), mchApplyment.getIfCode()); + cardInfo.put("auth_enturst_pic", f15); + + param.put("card_info", cardInfo); + if ("Y".equals(mchModifyData.getIllegal())) { + cardInfo.put("card_type", "2"); + } else { + if ("B".equals(mchModifyData.getSettAccountType())) { + cardInfo.put("card_type", "0"); + } else { + cardInfo.put("card_type", "1"); + } + } + + if (!"B".equals(mchModifyData.getSettAccountType())) { + cardInfo.put("prov_id", mchModifyData.getSettAccountBankBranchAreaCode().getString(0)); + cardInfo.put("area_id", mchModifyData.getSettAccountBankBranchAreaCode().getString(1)); + } else { + cardInfo.put("branch_code", mchModifyData.getBankSubCode()); + cardInfo.put("branch_name", mchModifyData.getSettAccountBankBranchName()); + } + + cardInfo.put("card_name", mchModifyData.getSettAccountName()); + cardInfo.put("card_no", mchModifyData.getSettAccountNo()); + cardInfo.put("bank_code", mchModifyData.getBankCode()); + + if ("Y".equals(mchModifyData.getIllegal())) { + cardInfo.put("cert_validity_type", mchModifyData.getSettAccountIdcardEffectEnd().equals("长期")? "1": "0"); + cardInfo.put("cert_begin_date", mchModifyData.getSettAccountIdcardEffectBegin().replace("-", "")); + if (!mchModifyData.getSettAccountIdcardEffectEnd().equals("长期")) { + cardInfo.put("cert_end_date", mchModifyData.getSettAccountIdcardEffectEnd().replace("-", "")); + } + cardInfo.put("cert_no", mchModifyData.getSettAccountIdcardNo()); + cardInfo.put("cert_type", "00"); + cardInfo.put("mp", mchModifyData.getPhone()); + } + + + if ("Y".equals(mchModifyData.getIllegal())) { + cardInfo.put("card_type", "2"); + } + + cardInfo.put("card_type", mchModifyData.getMchShortName()); + cardInfo.put("receipt_name", mchModifyData.getMchShortName()); + param.put("deal_type", "1"); + + JSONObject agreementInfo = new JSONObject(); + agreementInfo.put("agreement_type", "0"); + param.put("agreement_info", agreementInfo.toJSONString()); + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + try { + JSONObject applyResp = DgPayKit.request(mchAppConfigContext, param, DgPayKit.MCH_APPLY_MODIFY_URL, mchApplyment.getIfCode()); + JSONObject applyRespData = applyResp.getJSONObject("data"); + String code = applyRespData.getString("sub_resp_code"); + String msg = applyRespData.getString("sub_resp_desc"); + + if ("00000000".equals(code)) { + // 请求成功 + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else if ("90000000".equals(code)) { + // 审核中 + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + // 其他暂定为失败 + resultModifyApplyment.setApplyErrorInfo("[" + msg + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + String changeSysFlowId = applyRespData.getString("changeSysFlowId"); + + resultModifyApplyment.setChannelApplyNo(changeSysFlowId); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String remark = "斗拱支付结算信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("斗拱支付结算信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + DgpayApplymentInfo applymentInfo = JSON.parseObject(mchDataPair.right.getApplyDetailInfo(), DgpayApplymentInfo.class); + + DgpayIsvParams isvParams = ((DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + Date today = new Date(); + String formatDate = DateUtil.format(today, DatePattern.PURE_DATE_PATTERN); + param.put("req_seq_id", formatDate + mchModifyApplyment.getApplyId()); + param.put("req_date", formatDate); + param.put("upper_huifu_id", isvParams.getSysId()); + param.put("huifu_id", mchApplyment.getChannelMchNo()); + + JSONObject settleConfig = new JSONObject(); + settleConfig.put("settle_status", "1"); + settleConfig.put("settle_cycle", mchModifyData.getSettlementType()); + + PaywayFee d0 = null; + PaywayFee d1 = null; + for (PaywayFee paywayFee : applymentInfo.getPaywayFeeList()) { + if (CS.PAY_WAY_CODE.D0.equals(paywayFee.getFeeType())) { + d0 = paywayFee; + } + if (CS.PAY_WAY_CODE.D1.equals(paywayFee.getFeeType())) { + d1 = paywayFee; + } + } + + if (d1 != null) { + settleConfig.put("fixed_ratio", DgpayApplymentInfo.convertRate(d1.getFeeRate())); + } else { + // 默认D1提现费率为0.01% + settleConfig.put("fixed_ratio", "0.01"); + } + + param.put("settle_config", settleConfig.toJSONString()); + + JSONObject signUserInfo = new JSONObject(); + signUserInfo.put("type", "LEGAL"); + signUserInfo.put("mobile_no", mchApplyment.getContactPhone()); + + param.put("sign_user_info", signUserInfo); + + param.put("async_return_url", getCallbackUrl(mchApplyment.getIfCode())); + + JSONObject cashConfig = new JSONObject(); + param.put("deal_type", "2"); + + cashConfig.put("switch_state", "0"); + cashConfig.put("cash_type", mchModifyData.getSettlementType()); + + + + if (d0 != null) { + cashConfig.put("fee_rate", DgpayApplymentInfo.convertRate(d0.getFeeRate())); + } else { + // 默认D0提现费率设置为 0.1% + cashConfig.put("fee_rate", "0.10"); + } + + // 电子协议 + JSONObject agreementInfo = new JSONObject(); + agreementInfo.put("agreement_type", "0"); + param.put("agreement_info", agreementInfo.toJSONString()); + + // 结算卡信息 + JSONObject cardInfoJson = new JSONObject(); + + DgpayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + String settAccountType = info.getSettAccountType(); + if ("B".equals(settAccountType)) { + // 对公 + cardInfoJson.put("card_type", "0"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", ""); + // 银行编码 + cardInfoJson.put("bank_code", info.getBankCode()); + // 联行号 + cardInfoJson.put("branch_code", info.getBranchCode()); + // 支行名称 + cardInfoJson.put("branch_name", info.getBranchName()); + + cardInfoJson.put("mp", ""); + + // 签约人类型 +// signUserInfoJson.put("type", "LEGAL"); + + } else if ("C".equals(settAccountType)) { + cardInfoJson.put("mp", info.getSettAccountBindPhone()); + + // 对私 + cardInfoJson.put("card_type", "1"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", "00"); + // 持卡人证件号码 + cardInfoJson.put("cert_no", info.getSettAccountIdcardNo()); + // 持卡人证件有效期类型 + cardInfoJson.put("cert_validity_type", info.getCertValidityType(info.getSettAccountIdcardEffectEnd())); + // 持卡人证件有效期 起始 + cardInfoJson.put("cert_begin_date", info.getSettAccountIdcardEffectBegin().replace("-", "")); + // 持卡人证件有效期 截止 + if (!"长期".equals(info.getSettAccountIdcardEffectEnd())) { + cardInfoJson.put("cert_end_date", info.getSettAccountIdcardEffectEnd().replace("-", "")); + } + // 结算卡正面 +// fileJson.put("settle_card_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F13", info.getSettAccountLicenseImg(), mchApplyment.getIfCode())); +// // 结算卡反面 +// fileJson.put("settle_card_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F14", info.getSettBankCardBackImg(), mchApplyment.getIfCode())); +// // 结算人身份证人像面 +// fileJson.put("settle_cert_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F55", info.getSettAccountIdcard1Img(), mchApplyment.getIfCode())); +// // 结算人身份证国徽面 +// fileJson.put("settle_cert_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F56", info.getSettAccountIdcard2Img(), mchApplyment.getIfCode())); +// // 授权委托书 +// fileJson.put("auth_enturst_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F15", info.getAuthEnturstPic(), mchApplyment.getIfCode())); +// +// // 签约人类型 +// signUserInfoJson.put("type", "LEGAL"); + } else { + cardInfoJson.put("mp", info.getSettAccountBindPhone()); + // 对私非法人 + cardInfoJson.put("card_type", "2"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", "00"); + // 持卡人证件号码 + cardInfoJson.put("cert_no", info.getSettAccountIdcardNo()); + // 持卡人证件有效期类型 + cardInfoJson.put("cert_validity_type", info.getCertValidityType(info.getSettAccountIdcardEffectEnd())); + // 持卡人证件有效期 起始 + cardInfoJson.put("cert_begin_date", info.getSettAccountIdcardEffectBegin().replace("-", "")); + // 持卡人证件有效期 截止 + if (!"长期".equals(info.getSettAccountIdcardEffectEnd())) { + cardInfoJson.put("cert_end_date", info.getSettAccountIdcardEffectEnd().replace("-", "")); + } +// // 结算卡正面 +// fileJson.put("settle_card_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F13", info.getSettAccountLicenseImg(), mchApplyment.getIfCode())); +// // 结算卡反面 +// fileJson.put("settle_card_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F14", info.getSettBankCardBackImg(), mchApplyment.getIfCode())); +// // 结算人身份证人像面 +// fileJson.put("settle_cert_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F55", info.getSettAccountIdcard1Img(), mchApplyment.getIfCode())); +// // 结算人身份证国徽面 +// fileJson.put("settle_cert_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F56", info.getSettAccountIdcard2Img(), mchApplyment.getIfCode())); +// // 授权委托书 +// fileJson.put("auth_enturst_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F15", info.getAuthEnturstPic(), mchApplyment.getIfCode())); +// // 签约人法人授权书 +// fileJson.put("sign_auth_file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F245", info.getSignAuthFileId(), mchApplyment.getIfCode())); +// +// // 签约人类型 +// signUserInfoJson.put("type", "OTHER"); + } + // 卡户名 + cardInfoJson.put("card_name", info.getSettAccountName()); + // 银行卡号 + cardInfoJson.put("card_no", info.getSettAccountNo()); + // 银行所在省 + cardInfoJson.put("prov_id", info.getSettAccountBankBranchAreaCode().get(0)); + // 银行所在市 + cardInfoJson.put("area_id", info.getSettAccountBankBranchAreaCode().get(1)); + // 银行卡绑定手机号 + cardInfoJson.put("mp", info.getSettAccountBindPhone()); + + param.put("card_info", cardInfoJson.toJSONString()); + + JSONArray casArr = new JSONArray(); + casArr.add(cashConfig); + param.put("cash_config", casArr.toJSONString()); + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + try { + JSONObject applyResp = DgPayKit.request(mchAppConfigContext, param, DgPayKit.MCH_APPLY_MODIFY_URL, mchApplyment.getIfCode()); + JSONObject applyRespData = applyResp.getJSONObject("data"); + String code = applyRespData.getString("resp_code"); + String msg = applyRespData.getString("resp_desc"); + + if ("00000000".equals(code)) { + // 请求通过 + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + + return localModifySettlementType(mchDataPair); + } else if ("90000000".equals(code)) { + String applyNo = applyRespData.getString("apply_no"); + resultModifyApplyment.setChannelApplyNo(applyNo); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + msg + "]"); + } + + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + + String remark = "斗拱支付结算方式变更已发起"; + resultModifyApplyment.setRemark(remark); + log.info("斗拱支付结算方式变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + resultModifyApplyment.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + MchApplyment mchApplyment = mchDataPair.getValue(); + + JSONObject reqParams = new JSONObject(); + reqParams.put("huifu_id", mchApplyment.getChannelMchNo()); + reqParams.put("apply_no", modifyApplyment.getChannelApplyNo()); + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, DgPayKit.MCH_APPLY_QUERY_URL, mchApplyment.getIfCode()); + + JSONObject bizData = response.getJSONObject("data"); + String code = bizData.getString("resp_code"); + if ("00000000".equals(code)) { + String applStatus = bizData.getString("apply_status"); + if ("Y".equals(applStatus)) { + // 审核通过 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + return handleSuccessCase(modifyApplyment, mchDataPair); + } + if ("N".equals(applStatus) || "F".equals(applStatus)) { + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + bizData.getString("note") + "]"); + + return new MutablePair<>(resultModifyApplyment, null); + } + + if ("P".equals(applStatus)) { + // 审核中,需要查询签约状态 + JSONObject signReqParams = new JSONObject(); + signReqParams.put("huifu_id", mchApplyment.getChannelMchNo()); + JSONObject signResp = DgPayKit.request(mchAppConfigContext, signReqParams, DgPayKit.MCH_INFO_QUERY_URL, mchApplyment.getIfCode()); + JSONObject signRespBizData = signResp.getJSONObject("data"); + String respCode = signRespBizData.getString("resp_code"); + + if ("00000000".equals(respCode)) { + JSONArray agreementInfoList = signRespBizData.getJSONArray("agreement_info_list"); + + JSONObject item = agreementInfoList.getJSONObject(0); + + String conStat = item.getString("con_stat"); + + if ("3".equals(conStat)) { + // 待签约 + resultModifyApplyment.setState(MchApplyment.STATE_WAIT_SIGN); + + return new MutablePair<>(resultModifyApplyment, null); + } + + if ("5".equals(conStat)) { + // 签约完成 + resultModifyApplyment.setState(MchApplyment.STATE_FINISH_SIGN); + + return new MutablePair<>(resultModifyApplyment, null); + } + } + } + } + + return mchDataPair; + } + + private MutablePair handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair mchDataPair) { + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + return localModifySettlementType(mchDataPair); + default: + return mchDataPair; + } + } + + private String processChannelValue(String channelVal, JSONObject bizData) { + JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal); + channelValJSON.putAll(bizData); + return channelValJSON.toJSONString(); + } + + protected String getCallbackUrl(String ifCode) { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + ifCode; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchWxConfigService.java new file mode 100644 index 0000000..5dc7bf0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayIsvmchWxConfigService.java @@ -0,0 +1,227 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +@Service +@Slf4j +public class DgpayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + // 服务商配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode()); + + if (suJson == null || StringUtils.isEmpty(suJson.getString("huifuId"))) { + result.setState("查询失败"); + result.setErrInfo("商户参数为空,该商户还未进件成功"); + return result; + } + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxOpenUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + // 请求参数 + JSONObject reqParams = new JSONObject(); + // 汇付ID + reqParams.put("huifu_id", suJson.getString("huifuId")); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + ""); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/busi/realname/query", mchApplyment.getIfCode()); + + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis() + "_info"); + // 商户详情is_open_small_flag -> 0 + JSONObject mchInfoData = DgPayKit.request(mchAppConfigContext, reqParams, "/merchant/basicdata/query", mchApplyment.getIfCode()).getJSONObject("data"); + + String respCode = mchInfoData.getString("resp_code"); + String respDesc = mchInfoData.getString("resp_desc"); + + if (!respCode.equals("00000000")) { + result.setState("获取子商户状态异常"); + result.setErrInfo("【" + respDesc + "】"); + result.setImgType("qrContent"); + result.setSignUrl(isvParams.getAliChannelExtUrl()); + return result; + } + + String feeConfig = ""; + JSONArray wxConfList = mchInfoData.getJSONArray("qry_wx_conf_list"); + JSONArray aliConfList = mchInfoData.getJSONArray("qry_ali_conf_list"); + JSONObject unionConf = mchInfoData.getJSONObject("qry_union_conf"); + JSONObject bankCardConf = mchInfoData.getJSONObject("qry_bank_card_conf"); + log.info("【商户信息】微信配置:{}, 支付宝配置:{}, 银联配置:{}, 银行卡配置:{}", wxConfList, aliConfList, unionConf, bankCardConf); + + if (!CollUtil.isEmpty(wxConfList)) { + feeConfig = "【微信费率配置成功】"; + } + if (!CollUtil.isEmpty(aliConfList)) { + feeConfig = feeConfig + "【支付宝费率配置成功】"; + } + if (!CollUtil.isEmpty(unionConf)) { + feeConfig = feeConfig + "【银联费率配置成功】"; + } + if (!CollUtil.isEmpty(bankCardConf)) { + feeConfig = feeConfig + "【银行卡支付配置成功】"; + } + + for (int wxIndex = 0; wxIndex < wxConfList.size(); wxIndex++) { + JSONArray aliMerInfos = wxConfList.getJSONObject(wxIndex).getJSONArray("wx_mer_infos"); + + if (!CollUtil.isEmpty(aliMerInfos)) { + + for (int i = 0; i < aliMerInfos.size(); i++) { + JSONObject item = aliMerInfos.getJSONObject(i); + // 支付宝子商户号存在时 + MchSubInfoEntity wxSubInfo = new MchSubInfoEntity(); + wxSubInfo.setMchApplyId(mchApplyment.getApplyId()); + + String payChannelId = item.getString("pay_channel_id"); + String bankMerCode = item.getString("bank_mer_code"); + if (Objects.equals(isvParams.getChannelNo(), payChannelId)) { + wxSubInfo.setMainUse(1); + result.setChannelSubMchId(bankMerCode); + } else { + wxSubInfo.setMainUse(0); + } + wxSubInfo.setSubMchWay("DG"); + wxSubInfo.setChannelMchNo(mchApplyment.getChannelMchNo()); + wxSubInfo.setChannelId(payChannelId); + wxSubInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + wxSubInfo.setSubMchId(bankMerCode); + wxSubInfo.setSubMchType("WX"); + // 此处取1为正常 + wxSubInfo.setStatus("1"); + wxSubInfo.setExt(item); + + try { + mchSubInfoService.save(wxSubInfo); + } catch (DuplicateKeyException e) { + log.info("子商户信息已存储过"); + } + } + } + } + + result.setOriginData(feeConfig); + + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + // 驳回原因 + String rejectMsg = resData.getString("reject_reason"); + + // 请求异常 + if (!DgPayKit.STATE_SUCCESS.equals(code)) { + result.setErrInfo(resData.getString("resp_desc")); + return result; + } + + // 申请单状态 + String applymentStat = resData.getString("applyment_stat"); + // 授权状态 + String authorizeStat = resData.getString("authorize_stat"); + +// // 小程序码 +// result.setSignUrl(resData.getString("qrcode_data")); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + // 覆写状态 + if (StringUtils.isNotEmpty(authorizeStat)) { + if ("0".equals(authorizeStat)) { + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + result.setState("未授权"); + } else if ("1".equals(authorizeStat)) { + result.setState("已授权"); // 覆写状态 , 其他不考虑 + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApiService.java new file mode 100644 index 0000000..4b1710a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApiService.java @@ -0,0 +1,174 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +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 com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; + +/** + * TODO + * + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class DgpayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * + * @param applyment + * @param mchRq + * 01-标准费率线上(支持统一进件页面版) + * 02-标准费率线下(支持统一进件页面版) + * 03-非盈利行业费率 + * 04-缴费行业费率 + * 05-保险行汪费率 + * 06-行业(蓝海绿洲)活动场景费率 + * 07-校园餐饮费率 + * 08-K12中小幼费率 + * 09-非在线教培行业费率 + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + JSONObject bizData = new JSONObject(); + bizData.put("req_seq_id", getIfCode() + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN)); + bizData.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + bizData.put("huifu_id",applyment.getChannelMchNo()); + if(ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())){ + bizData.put("wx_woa_path",mchRq.getJsapiPath()); + }else if(ChannelMchRq.Type.PUBLIC.getType().equals(mchRq.getType())){ + bizData.put("wx_woa_app_id",mchRq.getAppid()); + }else if(ChannelMchRq.Type.APPLET.getType().equals(mchRq.getType())){ + bizData.put("wx_applet_app_id",mchRq.getAppid()); + } + //默认写死 还不知道作用是什么 传线下 + bizData.put("fee_type","02"); + + DgpayIsvParams isvParams = ((DgpayIsvParams) configContextQueryService.queryIsvParams(applyment)); + JSONObject respBizData = DgPayKit.req(DgPayKit.MCH_BUSI_CONFIG_URL, isvParams, bizData); + ChannelRetMsg retMsg = new ChannelRetMsg(); + retMsg.setChannelBizData(respBizData); + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return retMsg; + } + + /** + * 斗拱结算信息查询接口 + * @param settleRq + * @param isvNo + * @return + */ + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, DgpayIsvParams isvParams) { + if(StringUtils.isBlank(settleRq.getMercNo())){ + throw new BizException("缺失商户号"); + } + JSONObject bizData = new JSONObject(); + bizData.put("req_seq_id",getIfCode() + DateUtil.format(new DateTime(),DatePattern.PURE_DATETIME_MS_FORMATTER)); + bizData.put("req_date",DateUtil.format(new DateTime(),DatePattern.PURE_DATE_PATTERN)); + bizData.put("huifu_id",settleRq.getMercNo()); + bizData.put("begin_date",DateUtil.format(settleRq.getStartDate(),DatePattern.PURE_DATE_PATTERN)); + bizData.put("end_date",DateUtil.format(settleRq.getEndDate(),DatePattern.PURE_DATE_PATTERN)); + bizData.put("page_num",settleRq.getPage()); + bizData.put("page_size",settleRq.getSize()); + JSONObject respBizData = DgPayKit.req(DgPayKit.MCH_BUSI_SETTLE_QUERY_URL, isvParams, bizData); + JSONArray infos = respBizData.getJSONArray("trans_log_result_list"); + if(infos == null || infos.isEmpty()){ + return null; + } + List result = new ArrayList<>(infos.size()); + infos.forEach(item -> { + JSONObject itemData = ((JSONObject) item); + JSONObject stlData = new JSONObject(); + stlData.put("billNo",itemData.getString("trans_id")); + stlData.put("isvNo", isvNo); + stlData.put("settleDate",DateUtil.format(DateUtil.parse(itemData.getString("trans_date"),DatePattern.PURE_DATE_PATTERN),DatePattern.NORM_DATE_PATTERN)); + stlData.put("accountNo",itemData.getString("card_no")); + stlData.put("accountName",itemData.getString("card_name")); + stlData.put("settleAmt",itemData.getBigDecimal("trans_amt").multiply(BigDecimal.valueOf(100)).longValue()); +// long feeAmt = itemData.getBigDecimal("fee_amt").multiply(BigDecimal.valueOf(100)).longValue(); +// if( feeAmt > 0L){ +// stlData.put("fee",feeAmt); +// } + stlData.put("remark",itemData.getString("settle_desc")); + SettleState val = SettleState.getVal(itemData.getString("trans_stat")); + switch (val){ + case PAY_SUCCESS: + stlData.put("state", SettleInfo.SUCCESS); + break; + case PAY_FAIL: + stlData.put("state", SettleInfo.FAIL); + break; + case PAY_PROGRESS: + stlData.put("state", SettleInfo.PROGRESS); + break; + } + stlData.put("channelState",val.getState()); + result.add(stlData); + }); + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState{ + + PAY_PROGRESS("I","付款中"), + + PAY_SUCCESS("S","付款成功"), + + PAY_FAIL("F","付款失败"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state){ + SettleState[] values = values(); + for (SettleState val:values) { + if(val.getState().equals(state)){ + return val; + } + } + return PAY_PROGRESS; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApplymentService.java new file mode 100644 index 0000000..41aad89 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayMchApplymentService.java @@ -0,0 +1,815 @@ + +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.DgpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.service.impl.RateConfigService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.dgpay.utils.DgUtils; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * 斗拱接口进件 + * + * @author xiaoyu + * @date 2022/6/7 10:23 + */ +@Service +@Slf4j +public class DgpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private RateConfigService rateConfigService; + + @Override + public 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); + + DgpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + result.setSettlementType(applymentInfo.getSettleCycle()); + + return result; + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + String logPrefix = "【斗拱商户进件】"; + MchApplyment result = new MchApplyment(); + try { + + // 如果未进件成功执行第一次进件方法 + String succResParameter = mchApplyment.getSuccResParameter(); + if (StringUtils.isEmpty(succResParameter)) { + return firstApplyment(mchApplyment); + } + + JSONObject succJson = JSON.parseObject(succResParameter); + String huifuId = succJson.getString("huifuId"); + // 缺少必要参数 执行第一次进件 + if (StringUtils.isEmpty(huifuId)) { + return firstApplyment(mchApplyment); + } + + // 获取支付参数 + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + // 获取详细参数 + JSONObject reqParams = getApplymentParams(mchApplyment); + reqParams.put("huifu_id", huifuId); + // 业务处理类型 1:基本信息修改 2:业务开通 3:业务修改 4:审核材料补充(审核材料补充除必填字段外仅需要传入file_info字段) + reqParams.put("deal_type", "3"); + + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, DgPayKit.MCH_APPLY_UPDATE_URL, mchApplyment.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + if ("00000000".equals(code)) { + // 渠道号 + String channelOrderNo = resData.getString("apply_no"); + result.setChannelApplyNo(channelOrderNo); + // 进件响应参数 + result.setChannelVar1(resData.toJSONString()); + result.setState(MchApplyment.STATE_AUDITING); + } else if ("90000000".equals(code)) { + result.setState(MchApplyment.STATE_AUDITING); + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(code + "[" + resData.getString("resp_desc") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, code, resData.getString("resp_desc")); + return result; + } + + } catch (Exception e) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 进件失败:", logPrefix, e); + } + return result; + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + String logPrefix = "【斗拱商户进件状态查询】"; + MchApplyment result = new MchApplyment(); + try { + String succResParameter = mchApplyment.getSuccResParameter(); + JSONObject succJson = JSON.parseObject(succResParameter); + String huifuId = succJson.getString("huifuId"); + // 获取支付参数 + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB) + .setMchApplyment(mchApplyment); + + // 请求参数 + JSONObject reqParams = new JSONObject(); + reqParams.put("huifu_id", huifuId); + reqParams.put("apply_no", mchApplyment.getChannelApplyNo()); + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + reqParams.put("req_seq_id", DateKit.currentTimeMillis()); + // 发送请求 + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, DgPayKit.MCH_APPLY_QUERY_URL, mchApplyment.getIfCode()); + + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + if ("00000000".equals(code)) { + String applStatus = resData.getString("apply_status"); + // 入驻状态 + String regStatus = resData.getString("reg_status"); + if ("Y".equals(applStatus)) { + // 进件查询响应参数 +// result.setChannelVar1(resData.toJSONString()); + // 更新错误信息 + result.setApplyErrorInfo(""); + result.setState(MchApplyment.STATE_WAIT_SIGN); + if ("S".equals(regStatus)) { + // 入驻成功 +// result.setChannelVar2(resData.toJSONString()); + result.setState(MchApplyment.STATE_SUCCESS); + result.setChannelMchNo(huifuId); + + // 参数重写 商户号+绑卡序列号 + queryMchInfo(result, mchAppConfigContext, huifuId, mchApplyment.getIfCode()); + + } else { + result.setApplyErrorInfo(code + "[" + resData.getString("apply_reason") + "]"); + } + } else if ("P".equals(applStatus)) { + if ("S".equals(regStatus)) { + result.setState(MchApplyment.STATE_WAIT_SIGN); + } else { + result.setState(MchApplyment.STATE_AUDITING); + } + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(code + "[" + resData.getString("apply_reason") + "]"); + } + } else if ("90000000".equals(code)) { + result.setState(MchApplyment.STATE_AUDITING); + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(code + "[" + resData.getString("resp_desc") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, code, resData.getString("resp_desc")); + return result; + } + + } catch (BizException e) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 进件失败:", logPrefix, e); + } catch (Exception e) { + log.info("未知异常", e); + throw new BizException(e.getMessage()); + } + return result; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + public JSONObject getApplymentParams(MchApplyment mchApplyment) { + // 获取支付参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + // 获取详细参数 + DgpayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + // 请求参数 + JSONObject reqParams = new JSONObject(); + // 文件信息 + JSONObject fileJson = new JSONObject(); + + // 认证信息 + JSONObject realNameInfoJson = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 业务申请编号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis()); + // 渠道商户号 + reqParams.put("upper_huifu_id", isvParams.getSysId()); + // ONLINE:线上场景,OFFLINE:线下场景,ALL线上线下 场景类型 + reqParams.put("scene_type", "1".equals(isvParams.getPayScene()) ? "OFFLINE" : "ONLINE"); + + // 实名认证类型 + realNameInfoJson.put("realname_info_type", "AW"); + // 支付场景 -- 线下场景 + realNameInfoJson.put("pay_scene", "1"); + + if (CollUtil.isEmpty(info.getAreaCode())) { + throw new BizException("请选择店铺经营省市区地址"); + } + + boolean bankAllow = DgUtils.checkBankLimitArea(info.getAreaCode().getString(0)); + + // 经营地址 省 + reqParams.put("prov_id", info.getAreaCode().get(0)); + // 经营地址 市 + reqParams.put("area_id", info.getAreaCode().get(1)); + // 经营地址 区 + reqParams.put("district_id", info.getAreaCode().get(2)); + // 详细经营地址 + reqParams.put("detail_addr", info.getAddress()); + + // 签约人 + JSONObject signUserInfoJson = new JSONObject(); + // 签约人类型 + signUserInfoJson.put("type", "LEGAL"); + + // 异步通知地址 + String notifyUrl = sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + CS.IF_CODE.DGPAY; + reqParams.put("async_return_url", notifyUrl); + reqParams.put("busi_async_return_url", notifyUrl); + // 是否发送短信通知到商户 设置为发送 + reqParams.put("sms_send_flag", "A"); + + // 卡信息 + JSONObject cardInfoJson = new JSONObject(); + String settAccountType = info.getSettAccountType(); + if ("B".equals(settAccountType)) { + // 对公 + cardInfoJson.put("card_type", "0"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", ""); + // 银行编码 + cardInfoJson.put("bank_code", info.getBankCode()); + // 联行号 + cardInfoJson.put("branch_code", info.getBranchCode()); + // 支行名称 + cardInfoJson.put("branch_name", info.getBranchName()); + + // 签约人类型 + signUserInfoJson.put("type", "LEGAL"); + + } else if ("C".equals(settAccountType)) { + // 对私 + cardInfoJson.put("card_type", "1"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", "00"); + // 持卡人证件号码 + cardInfoJson.put("cert_no", info.getSettAccountIdcardNo()); + // 持卡人证件有效期类型 + cardInfoJson.put("cert_validity_type", info.getCertValidityType(info.getSettAccountIdcardEffectEnd())); + // 持卡人证件有效期 起始 + cardInfoJson.put("cert_begin_date", info.getSettAccountIdcardEffectBegin().replace("-", "")); + // 持卡人证件有效期 截止 + if (!"长期".equals(info.getSettAccountIdcardEffectEnd())) { + cardInfoJson.put("cert_end_date", info.getSettAccountIdcardEffectEnd().replace("-", "")); + } + // 结算卡正面 + fileJson.put("settle_card_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F13", info.getSettAccountLicenseImg(), mchApplyment.getIfCode())); + // 结算卡反面 + fileJson.put("settle_card_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F14", info.getSettBankCardBackImg(), mchApplyment.getIfCode())); + // 结算人身份证人像面 + fileJson.put("settle_cert_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F55", info.getSettAccountIdcard1Img(), mchApplyment.getIfCode())); + // 结算人身份证国徽面 + fileJson.put("settle_cert_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F56", info.getSettAccountIdcard2Img(), mchApplyment.getIfCode())); + // 授权委托书 + fileJson.put("auth_enturst_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F15", info.getAuthEnturstPic(), mchApplyment.getIfCode())); + + // 签约人类型 + signUserInfoJson.put("type", "LEGAL"); + } else { + // 对私非法人 + cardInfoJson.put("card_type", "2"); + // 持卡人证件类型 默认为身份证 + cardInfoJson.put("cert_type", "00"); + // 持卡人证件号码 + cardInfoJson.put("cert_no", info.getSettAccountIdcardNo()); + // 持卡人证件有效期类型 + cardInfoJson.put("cert_validity_type", info.getCertValidityType(info.getSettAccountIdcardEffectEnd())); + // 持卡人证件有效期 起始 + cardInfoJson.put("cert_begin_date", info.getSettAccountIdcardEffectBegin().replace("-", "")); + // 持卡人证件有效期 截止 + if (!"长期".equals(info.getSettAccountIdcardEffectEnd())) { + cardInfoJson.put("cert_end_date", info.getSettAccountIdcardEffectEnd().replace("-", "")); + } + // 结算卡正面 + fileJson.put("settle_card_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F13", info.getSettAccountLicenseImg(), mchApplyment.getIfCode())); + // 结算卡反面 + fileJson.put("settle_card_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F14", info.getSettBankCardBackImg(), mchApplyment.getIfCode())); + // 结算人身份证人像面 + fileJson.put("settle_cert_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F55", info.getSettAccountIdcard1Img(), mchApplyment.getIfCode())); + // 结算人身份证国徽面 + fileJson.put("settle_cert_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F56", info.getSettAccountIdcard2Img(), mchApplyment.getIfCode())); + // 授权委托书 + fileJson.put("auth_enturst_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F15", info.getAuthEnturstPic(), mchApplyment.getIfCode())); + // 签约人法人授权书 + fileJson.put("sign_auth_file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F245", info.getSignAuthFileId(), mchApplyment.getIfCode())); + + // 签约人类型 + signUserInfoJson.put("type", "OTHER"); + } + // 卡户名 + cardInfoJson.put("card_name", info.getSettAccountName()); + // 银行卡号 + cardInfoJson.put("card_no", info.getSettAccountNo()); + // 银行所在省 + cardInfoJson.put("prov_id", info.getSettAccountBankBranchAreaCode().get(0)); + // 银行所在市 + cardInfoJson.put("area_id", info.getSettAccountBankBranchAreaCode().get(1)); + // 银行卡绑定手机号 + cardInfoJson.put("mp", info.getSettAccountBindPhone()); + // 结算卡信息 + reqParams.put("card_info", cardInfoJson); + // 结算配置 + JSONObject settConfig = new JSONObject(); + // 结算周期 + settConfig.put("settle_cycle", info.getSettleCycle()); + // 起结金额 + settConfig.put("min_amt", "0.00"); + // 留存金额 + settConfig.put("remained_amt", "0.00"); + + + if ("D1".equals(info.getSettleCycle())) { + // D1费率 [0.00 - 100.00] + + List paywayFeeList = info.getPaywayFeeList(); + for (PaywayFee paywayFee : paywayFeeList) { + if (CS.PAY_WAY_CODE.D1.equals(paywayFee.getWayCode())) { + settConfig.put("fixed_ratio", DgpayApplymentInfo.convertRate(paywayFee.getFeeRate())); + } + } + + settConfig.put("fixed_ratio", isvParams.getSettleFee()); + // D1结算协议图片文件 + if (StringUtils.isNotEmpty(info.getSettleAgreePic())) { + fileJson.put("settle_agree_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F116", info.getSettleAgreePic(), mchApplyment.getIfCode())); + } + } + reqParams.put("settle_config", settConfig.toJSONString()); + // 取现配置 + if (!"0".equals(isvParams.getMchSettManual())) { + JSONObject cashJson = new JSONObject(); + // 取现类型 + cashJson.put("cash_type", isvParams.getMchSettManual()); + if (StringUtils.isNotEmpty(isvParams.getCashFee())) { + cashJson.put("fee_rate", isvParams.getCashFee()); + } else { + cashJson.put("fix_amt", "0.00"); + cashJson.put("fee_rate", "0.00"); + } + JSONArray casArr = new JSONArray(); + casArr.add(cashJson); + reqParams.put("cash_config", casArr.toJSONString()); + } + + if (StringUtils.isNotEmpty(info.getLoginUserName())) { + // 管理员账号 + reqParams.put("login_name", info.getLoginUserName().trim()); + } + + // 所属行业MCC + reqParams.put("mcc", info.getMccCode()); + + // 个人商户 + if (info.getMerchantType() == 1) { + // 个人商户 + reqParams.put("ent_type", "0"); + // 商户名 + reqParams.put("reg_name", info.getContactName()); + // 商户简称 + reqParams.put("short_name", info.getMchFullName()); + JSONObject contactInfoJson = new JSONObject(); + // 联系人姓名 + contactInfoJson.put("contact_name", info.getContactName()); + // 联系人手机号 + contactInfoJson.put("contact_mobile_no", info.getContactPhone()); + // 联系人邮箱 + contactInfoJson.put("contact_email", info.getContactEmail()); + // 联系人身份证号 + contactInfoJson.put("contact_cert_no", info.getContactIdcardNo()); + // 联系人信息 + reqParams.put("contact_info", contactInfoJson); + // 签约人手机号 + signUserInfoJson.put("sign_mobile_no", info.getContactPhone()); + // 签约人姓名 + signUserInfoJson.put("name", info.getContactName()); + // 签约人手机号 + signUserInfoJson.put("mobile_no", info.getContactPhone()); + // 签约人身份证号 + signUserInfoJson.put("cert_no", info.getContactIdcardNo()); + // TODO **** 兼容 旧接口 **** + // 签约人姓名 + signUserInfoJson.put("sign_name", info.getContactName()); + // 签约人身份证号 + signUserInfoJson.put("sign_cert_no", info.getContactIdcardNo()); + + reqParams.put("sign_user_info", signUserInfoJson); + + // 联系人姓名 + realNameInfoJson.put("name", info.getContactName()); + // 联系人手机号 + realNameInfoJson.put("mobile", info.getContactPhone()); + // 联系人证件号 + realNameInfoJson.put("contact_id_card_number", info.getContactIdcardNo()); + + // 法人身份证人像面照片 + fileJson.put("identification_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F40", info.getIdcard1Img(), mchApplyment.getIfCode())); + // 法人身份证国徽面照片 + fileJson.put("identification_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F41", info.getIdcard2Img(), mchApplyment.getIfCode())); + + } else { + // 公司类型 + reqParams.put("ent_type", info.getEntType()); + // 商户名称 + reqParams.put("reg_name", info.getMchFullName()); + // 商户英文名称 + reqParams.put("mer_en_name", info.getMerEnName()); + // 经营名称 + reqParams.put("short_name", info.getMchShortName()); + // 小票名称 + reqParams.put("receipt_name", info.getReceiptName()); + // 经营类型 + reqParams.put("busi_type", info.getBusiType()); + // 注册资本 + reqParams.put("reg_capital", info.getRegCapital()); + + // 执照类型 NATIONAL_LEGAL-营业执照 NATIONAL_LEGAL_MERGE-多证合一 + reqParams.put("license_type", "NATIONAL_LEGAL"); + // 营业执照编号 + reqParams.put("license_code", info.getLicenseNo()); + // 经营范围 + reqParams.put("business_scope", info.getLicenseBusiness()); + + // 营业执照有效期类型 + reqParams.put("license_validity_type", info.getCertValidityType(info.getLicenseEffectEnd())); + // 营业执照有效期开始日期 + reqParams.put("license_begin_date", info.getLicenseEffectBegin().replace("-", "")); + // 营业执照有效期截止日期 + if (!"长期".equals(info.getLicenseEffectEnd())) { + reqParams.put("license_end_date", info.getLicenseEffectEnd().replace("-", "")); + } + + JSONObject contactInfoJson = new JSONObject(); + // 联系人姓名 + contactInfoJson.put("contact_name", info.getIdcardName()); + // 联系人手机号 + contactInfoJson.put("contact_mobile_no", info.getIdCardPhone()); + // 联系人邮箱 + contactInfoJson.put("contact_email", info.getIdCardEmail()); + // 联系人身份证号 + contactInfoJson.put("contact_cert_no", info.getIdcardNo()); + // 联系人信息 + reqParams.put("contact_info", contactInfoJson); + + // 非法人结算签约人信息 + if (StringUtils.isNotEmpty(info.getSettAccountType()) && "D".equals(info.getSettAccountType())) { + // 签约人手机号 + signUserInfoJson.put("sign_mobile_no", info.getSettAccountBindPhone()); + // 签约人姓名 + signUserInfoJson.put("name", info.getSettAccountName()); + // 签约人手机号 + signUserInfoJson.put("mobile_no", info.getSettAccountBindPhone()); + // 签约人身份证号 + signUserInfoJson.put("cert_no", info.getSettAccountIdcardNo()); + // TODO **** 兼容 旧接口 **** + // 签约人姓名 + signUserInfoJson.put("sign_name", info.getSettAccountName()); + // 签约人身份证号 + signUserInfoJson.put("sign_cert_no", info.getSettAccountIdcardNo()); + + } else { + // 签约人手机号 + signUserInfoJson.put("sign_mobile_no", info.getIdCardPhone()); + signUserInfoJson.put("mobile_no", info.getIdCardPhone()); + // 签约人姓名 + signUserInfoJson.put("name", info.getIdcardName()); + // 签约人身份证号 + signUserInfoJson.put("cert_no", info.getIdcardNo()); + + // TODO **** 兼容 旧接口 **** + // 签约人姓名 + signUserInfoJson.put("sign_name", info.getIdcardName()); + // 签约人身份证号 + signUserInfoJson.put("sign_cert_no", info.getIdcardNo()); + } + + reqParams.put("sign_user_info", signUserInfoJson); + + // 联系人姓名 + realNameInfoJson.put("name", info.getIdcardName()); + // 联系人手机号 + realNameInfoJson.put("mobile", info.getIdCardPhone()); + // 联系人证件号 + realNameInfoJson.put("contact_id_card_number", info.getIdcardNo()); + + // 注册 省 + reqParams.put("reg_prov_id", info.getAreaCode().get(0)); + // 注册 市 + reqParams.put("reg_area_id", info.getAreaCode().get(1)); + // 注册 区 + reqParams.put("reg_district_id", info.getAreaCode().get(2)); + // 注册地址 + reqParams.put("reg_detail", info.getAddress()); + + // 法人信息 + JSONObject legalInfoJson = new JSONObject(); + // 法人姓名 + legalInfoJson.put("legal_name", info.getIdcardName()); + // 法人证件类型 默认身份证 + legalInfoJson.put("legal_cert_type", "00"); + // 法人证件号码 + legalInfoJson.put("legal_cert_no", info.getIdcardNo()); + // 法人手机号 + legalInfoJson.put("legal_mobile_no", info.getIdCardPhone()); + // 法人证件居住地 + legalInfoJson.put("legal_identification_address", info.getIdcardAddress()); + // 法人证件有效期类型 + legalInfoJson.put("legal_cert_validity_type", info.getCertValidityType(info.getIdcardEffectEnd())); + // 法人证件有效期开始日期 + legalInfoJson.put("legal_cert_begin_date", info.getIdcardEffectBegin().replace("-", "")); + if ("0".equals(info.getCertValidityType(info.getIdcardEffectEnd()))) { + // 法人证件有效期截止日期 + legalInfoJson.put("legal_cert_end_date", info.getIdcardEffectEnd().replace("-", "")); + } + reqParams.put("legal_info", legalInfoJson); + + // 客服电话 + reqParams.put("service_phone", info.getServicePhone()); + + // 门头照 + reqParams.put("store_header_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F18", info.getStoreOuterImg(), mchApplyment.getIfCode())); + // 内景照 + reqParams.put("store_indoor_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F19", info.getStoreInnerImg(), mchApplyment.getIfCode())); + // 收银台照 + reqParams.put("store_cashier_desk_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F20", info.getStoreCashierImg(), mchApplyment.getIfCode())); + + // 开户许可证 + fileJson.put("reg_acct_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F08", info.getCompanyAccountLicenseImg(), mchApplyment.getIfCode())); + // 法人身份证人像面照片 + fileJson.put("legal_cert_front_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F02", info.getIdcard1Img(), mchApplyment.getIfCode())); + // 法人身份证国徽面照片 + fileJson.put("legal_cert_back_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F03", info.getIdcard2Img(), mchApplyment.getIfCode())); + // 营业执照 + fileJson.put("license_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F07", info.getLicenseImg(), mchApplyment.getIfCode())); + // 组织机构代码证 +// fileJson.put("org_code_pic", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F57", info.getOrgCodePic())); + // 签约人身份证照片-人像照 + fileJson.put("sign_identity_front_file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F244", info.getIdcard1Img(), mchApplyment.getIfCode())); + // 签约人身份证照片-国徽照 + fileJson.put("sign_identity_back_file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F247", info.getIdcard2Img(), mchApplyment.getIfCode())); + } + + // 扩展资料包 + JSONArray extendedList = new JSONArray(); + if (StringUtils.isNotEmpty(info.getServiceAgreement())) { + // 【商户】斗拱平台综合支付服务协议(纸质合同版) + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F479", info.getServiceAgreement(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F479"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getPriceConfirmation())) { + // 【商户】斗拱平台综合支付服务功能及价格确认表(纸质合同版) + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F480", info.getPriceConfirmation(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F480"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getStoreInnerImg())) { + // (线上场景)办公场所照片-工作区域 + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F371", info.getStoreInnerImg(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F371"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getStoreOuterImg())) { + // (线上场景)办公场所照片-公司前台 + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F478", info.getStoreOuterImg(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F478"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getStoreOuterImg())) { + // 门头照 + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F22", info.getStoreOuterImg(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F22"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getStoreInnerImg())) { + // 内景照 + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F24", info.getStoreInnerImg(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F24"); + extendedList.add(paramJson); + } + if (StringUtils.isNotEmpty(info.getStoreCashierImg())) { + // 收银台照 + JSONObject paramJson = JsonKit.newJson("file_id", DgPayKit.uploadFile(mchApplyment.getIsvNo(), "F105", info.getStoreCashierImg(), mchApplyment.getIfCode())); + paramJson.put("file_type", "F105"); + extendedList.add(paramJson); + } + + reqParams.put("extended_material_list", extendedList.toJSONString()); + + JSONObject agreementJson = new JSONObject(); + // 如果配置了协议信息 走电子协议 未配置则纸质协议 + if (StringUtils.isNotEmpty(isvParams.getAgreementModel())) { + // 协议类型 + agreementJson.put("agreement_type", "0"); + // 协议模板号 + agreementJson.put("agreement_model", isvParams.getAgreementModel()); + // 协议模板名称 + agreementJson.put("agreement_name", isvParams.getAgreementName()); + } else { + // 协议类型 + agreementJson.put("agreement_type", "1"); + } + reqParams.put("agreement_info", agreementJson.toJSONString()); + + // 业务开关配置 + JSONObject bizConfJson = new JSONObject(); + // 延迟入账开关 + bizConfJson.put("delay_flag", "Y"); + // 是否开通补贴支付 + bizConfJson.put("combine_pay_flag", "Y"); + // 是否开通余额支付 + bizConfJson.put("balance_pay_flag", "Y"); + // 是否开通结算 + bizConfJson.put("settle_flag", "Y"); +// // 商户开通强制延迟标记 +// bizConfJson.put("forced_delay_flag", "Y"); +// // 是否开通网银 +// bizConfJson.put("online_flag", "Y"); +// // 是否开通快捷 +// bizConfJson.put("quick_flag", "Y"); +// // 是否开通代扣 +// bizConfJson.put("withhold_flag", "Y"); +// // 是否开通微信预授权 +// bizConfJson.put("wechatpay_pre_auth_flag", "Y"); +// // 是否开通支付宝预授权 +// bizConfJson.put("alipay_pre_auth_flag", "Y"); + + reqParams.put("biz_conf", bizConfJson); + + + // 支付宝配置对象 + List aliPayFeeList = info.convertAliPayFee(isvParams); + if (CollUtil.isNotEmpty(aliPayFeeList)) { + reqParams.put("ali_conf_list", JSON.toJSONString(aliPayFeeList)); + } + + WxpayOauth2Params wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchApplyment.getIsvNo(), CS.IF_CODE.WXPAY); + DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig(); + // 微信配置对象 + List wxPayFeeList = info.convertWxPayFee(isvParams, wxpayOauth2Params, dbApplicationConfig); + if (CollUtil.isNotEmpty(wxPayFeeList)) { + reqParams.put("wx_conf_list", JSON.toJSONString(wxPayFeeList)); + } + + if (bankAllow) { + // 银联配置对象 + List unionList = info.convertUniPayFee(); + if (CollUtil.isNotEmpty(unionList)) { + reqParams.put("union_conf_list", unionList.toString()); + } + // 银行卡业务配置 + JSONObject bankPayFee = info.convertBankPayFee(); + if (bankPayFee != null && bankPayFee.size() > 1) { + reqParams.put("bank_card_conf", bankPayFee.toJSONString()); + } + // 银联小微参数配置 + if (CollUtil.isNotEmpty(unionList)) { + reqParams.put("union_micro_info", info.getMicroInfo()); + } + } + + // 文件集 + reqParams.put("file_info", fileJson); + // 实名认证信息 + reqParams.put("wx_realname_info", realNameInfoJson); + + return reqParams; + } + + public void setAccountInfo(MchApplyment mchApplyment, JSONObject reqParams) { + DgpayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), DgpayApplymentInfo.class); + if (info.getMerchantType() == 1) { + reqParams.put("name", info.getContactName()); + // 银行卡绑定手机号 + reqParams.put("mobile_no", info.getSettAccountBindPhone()); + // 持卡人证件类型 默认为身份证 + reqParams.put("cert_type", "00"); + // 持卡人证件号码 + reqParams.put("cert_no", info.getSettAccountIdcardNo()); + // 持卡人证件有效期类型 + reqParams.put("cert_validity_type", info.getCertValidityType(info.getSettAccountIdcardEffectEnd())); + // 持卡人证件有效期 起始 + reqParams.put("cert_begin_date", info.getSettAccountIdcardEffectBegin().replace("-", "")); + // 持卡人证件有效期 截止 + if (!"长期".equals(info.getSettAccountIdcardEffectEnd())) { + reqParams.put("cert_end_date", info.getSettAccountIdcardEffectEnd().replace("-", "")); + } + } else { + // 联系人姓名 + reqParams.put("contact_name", info.getIdcardName()); + // 联系人手机号 + reqParams.put("contact_mobile", info.getIdCardPhone()); + // 联系人邮箱 + reqParams.put("contact_email", info.getIdCardEmail()); + // 联系人身份证号 + reqParams.put("contact_cert_no", info.getIdcardNo()); + + // 法人姓名 + reqParams.put("legal_name", info.getIdcardName()); + // 法人证件类型 默认身份证 + reqParams.put("legal_cert_type", "00"); + // 法人证件号码 + reqParams.put("legal_cert_no", info.getIdcardNo()); + // 法人证件有效期类型 + reqParams.put("legal_cert_validity_type", info.getCertValidityType(info.getIdcardEffectEnd())); + // 法人证件有效期开始日期 + reqParams.put("legal_cert_begin_date", info.getIdcardEffectBegin().replace("-", "")); + if ("0".equals(info.getCertValidityType(info.getIdcardEffectEnd()))) { + // 法人证件有效期截止日期 + reqParams.put("legal_cert_end_date", info.getIdcardEffectEnd().replace("-", "")); + } + } + // 发送短信标识 + reqParams.put("sms_send_flag", "Y"); + + reqParams.remove("area_id"); + reqParams.remove("detail_addr"); + reqParams.remove("prov_id"); + reqParams.remove("district_id"); + reqParams.remove("busi_type"); + reqParams.remove("mcc"); + reqParams.remove("receipt_name"); + reqParams.remove("ent_type"); + reqParams.remove("upper_huifu_id"); + reqParams.put("noMchId", true); + } + + /** + * 查询商户详细信息 + **/ + public void queryMchInfo(MchApplyment result, MchAppConfigContext mchAppConfigContext, String huifuId, String ifCode) { + String logPrefix = "【斗拱】查询商户详细信息"; + try { + // 请求参数 + JSONObject reqParams = new JSONObject(); + reqParams.put("huifu_id", huifuId); + // 发送请求 + log.info("{}请求开始", logPrefix); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, DgPayKit.MCH_INFO_QUERY_URL, ifCode); + log.info("{}请求结束", logPrefix); + + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + if ("00000000".equals(code)) { + JSONArray infoList = resData.getJSONArray("qry_cash_card_info_list"); + if (CollUtil.isNotEmpty(infoList)) { + // 取第一个卡信息 + JSONObject infoJson = (JSONObject) JSON.toJSON(infoList.get(0)); + // 绑卡序列号 + String tokenNo = infoJson.getString("token_no"); + DgpayIsvsubMchParams mchParams = new DgpayIsvsubMchParams(); + mchParams.setHuifuId(huifuId); + mchParams.setTokenNo(tokenNo); + result.setSuccResParameter(JSON.toJSONString(mchParams)); + } + + + } + } catch (Exception e) { + log.error("{} 异常:", logPrefix, e); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderCloseService.java new file mode 100644 index 0000000..0d0a7c5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderCloseService.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** + * 订单关闭 + * + * @author xiaoyu + * + * @date 2023/2/28 16:30 + */ +@Service +public class DgpayPayOrderCloseService implements IPayOrderCloseService { + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + JSONObject reqParams = new JSONObject(); + // 请求日期 + reqParams.put("req_date", DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)); + // 请求流水号 + reqParams.put("req_seq_id", DateKit.currentTimeMillis()+""); + // 交易流水号 + reqParams.put("org_hf_seq_id", payOrder.getChannelOrderNo()); + // 商户号 + reqParams.put("huifu_id", payOrder.getChannelMchNo()); + // 原机构请求日期 + reqParams.put("org_req_date", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/scanpay/close", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + //如果查询请求成功 + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String transStat = resData.getString("trans_stat"); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + return ChannelRetMsg.confirmSuccess(null); + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + // 失败 + return ChannelRetMsg.confirmFail(resData.getString("resp_desc")); + } + }else if(DgPayKit.STATE_ING.equals(code)) { + return ChannelRetMsg.confirmSuccess(null); + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderQueryService.java new file mode 100644 index 0000000..9b54731 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPayOrderQueryService.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 查询订单 + * + * @author xiaoyu + * + * @date 2022/6/9 17:05 + */ +@Service +@Slf4j +public class DgpayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + // 智能POS 直接返回 + if (StringUtils.equals(payOrder.getWayCode(), CS.PAY_WAY_CODE.AUTO_POS)) { + return ChannelRetMsg.waiting(); + } + try { + JSONObject reqParams = new JSONObject(); + // 交易流水号 + reqParams.put("mer_ord_id", payOrder.getPayOrderId()); + // 商户号 + reqParams.put("huifu_id", payOrder.getChannelMchNo()); + // 原机构请求日期 + reqParams.put("org_req_date", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/scanpay/query", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + //如果查询请求成功 + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String tradeState = resData.getString("trans_stat"); + if (DgPayKit.STATE_SUCCESS_S.equals(tradeState)) { + String channelOrderNo = resData.getString("org_hf_seq_id"); + // 渠道订单号 + String outTransId = resData.getString("out_trans_id"); + // 商户订单号 + String partyOrderId = resData.getString("party_order_id"); + String drType = CS.DrType.OTHER.getType(); + String debit_type = resData.getString("debit_type"); + if("D".equals(debit_type)){ + drType = CS.DrType.DEBIT.getType(); + }else if("C".equals(debit_type)){ + drType = CS.DrType.CREDIT.getType(); + } + return ChannelRetMsg.confirmSuccess(channelOrderNo, outTransId, partyOrderId,drType); + }else if (DgPayKit.STATE_FAIL_F.equals(tradeState)) { + // 失败 + return ChannelRetMsg.confirmFail(); + } + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPaymentService.java new file mode 100644 index 0000000..53a168f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPaymentService.java @@ -0,0 +1,42 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import org.springframework.stereotype.Service; + +/** + * * 支付接口: 斗拱 + * + * @author xiaoyu + * + * @date 2022/5/13 15:02 + */ +@Service +public class DgpayPaymentService extends AbstractPaymentService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPosNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPosNoticeService.java new file mode 100644 index 0000000..83a8ac1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayPosNoticeService.java @@ -0,0 +1,169 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.autopos.ChannelOrderAcceptParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractPosNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Triple; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 富友智能POS回调 + * + * @author zx + * + * @date 2021-06-07 07:15 + */ +@Service +@Slf4j +public class DgpayPosNoticeService extends AbstractPosNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public Triple parseParams(HttpServletRequest request) { + + JSONObject params = getReqParamJSON(); + + String respCode = params.getString("resp_code"); + if (!StringUtils.equals(DgPayKit.STATE_SUCCESS, respCode)) { + log.info("汇付斗拱智能POS【订单推送模式】回调处理失败,resp_code={}", respCode); + throw ResponseException.buildText("ERROR"); + } + + // 交易数据 + JSONObject respData = params.getJSONObject("resp_data"); + String subRespCode = respData.getString("sub_resp_code"); + if (!StringUtils.equals(DgPayKit.STATE_SUCCESS, subRespCode)) { + log.info("汇付斗拱智能POS【订单推送模式】回调处理失败,sub_resp_code={}", subRespCode); + throw ResponseException.buildText("ERROR"); + } + + String payOrderId = respData.getString("mer_ord_id"); + String transType = respData.getString("trans_type"); // TRANS_REFUND: 交易退款 SCAN_REFUND: 终端扫码退款 + + String tradeType = ""; + if (StringUtils.isNotBlank(transType)) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_PAYMENT; + + if (StringUtils.equalsAny(transType, "TRANS_REFUND", "SCAN_REFUND")) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_REFUND; + } + } + + log.info("斗拱智能POS【订单推送模式】通知参数:tradeType={},params={}", tradeType, params.toJSONString()); + return Triple.of(tradeType, payOrderId, params); + } + + @Override + public ChannelRetMsg payNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + String logPrefix = "处理斗拱智能POS【订单推送模式】支付回调"; + JSONObject jsonParams = (JSONObject) params; + + // 验签 + validate(jsonParams, mchAppConfigContext, payOrder.getIfCode(), logPrefix); + + // 获取请求参数 + JSONObject respData = jsonParams.getJSONObject("resp_data"); + + String transAmt = AmountUtil.convertDollar2Cent(respData.getString("trans_amt")); + if (!String.valueOf(payOrder.getAmount()).equals(transAmt)) { + log.error("{} 金额不符,trans_amt={},amount={}", logPrefix, transAmt, payOrder.getAmount()); + throw ResponseException.buildText("ERROR"); + } + + // 判断上游订单状态 + ResponseEntity okResponse = textResp("RECV_ORD_ID_" + payOrder.getPayOrderId()); + + ChannelRetMsg result = new ChannelRetMsg(); + // 默认支付中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + String transStat = respData.getString("trans_stat"); // 支付状态 I:初始、P:处理中、S:成功、F:失败 + if(DgPayKit.STATE_SUCCESS_S.equals(transStat)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if(DgPayKit.STATE_FAIL_F.equals(transStat)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + result.setResponseEntity(okResponse); + result.setChannelOrderId(respData.getString("req_seq_id")); + return result; + } + + @Override + public ChannelRetMsg refundNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "处理斗拱智能POS【订单推送模式】退款通知"; + + JSONObject jsonParams = (JSONObject) params; + + // 验签 + validate(jsonParams, mchAppConfigContext, refundOrder.getIfCode(), logPrefix); + + // 获取请求参数 + JSONObject respData = jsonParams.getJSONObject("resp_data"); + String transAmt = AmountUtil.convertDollar2Cent(respData.getString("ord_amt")); + if (!String.valueOf(refundOrder.getRefundAmount()).equals(transAmt)) { + log.error("{} 金额不符,ord_amt={},amount={}", logPrefix, transAmt, refundOrder.getRefundAmount()); + throw ResponseException.buildText("ERROR"); + } + + // 判断上游订单状态 + ResponseEntity okResponse = textResp("RECV_ORD_ID_" + refundOrder.getRefundOrderId()); + + ChannelRetMsg result = new ChannelRetMsg(); + // 默认支付中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + String transStat = respData.getString("trans_stat"); // 支付状态 I:初始、P:处理中、S:成功、F:失败 + if(DgPayKit.STATE_SUCCESS_S.equals(transStat)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if(DgPayKit.STATE_FAIL_F.equals(transStat)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + result.setResponseEntity(okResponse); + result.setChannelOrderId(respData.getString("hf_seq_id")); + return result; + } + + /** + * 验签 + * @return + */ + private void validate(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, String ifCode, String logPrefix) { + + String sign = jsonParams.getString("sign"); + + // 公钥参数 + DgpayIsvParams isvParams = (DgpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + + // 验证签名 + boolean verifyResult = DgPayKit.verify(jsonParams.getString("resp_data"), isvParams.getPosPublicKey(), sign); + // 验签失败 + if(!verifyResult){ + log.error("{} 验签失败", logPrefix); + throw ResponseException.buildText("SIGN ERROR"); + } + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayRefundService.java new file mode 100644 index 0000000..509c080 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/DgpayRefundService.java @@ -0,0 +1,239 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 斗拱 + * + * @author xiaoyu + * + * @date 2022/6/9 17:43 + */ +@Slf4j +@Service +public class DgpayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.DGPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + // 智能pos收款,走独立退款接口 + if (StringUtils.equals(payOrder.getWayCode(), CS.PAY_WAY_CODE.AUTO_POS)) { + return autoPosRefund(bizRQ, refundOrder, payOrder, mchAppConfigContext); + } + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject reqParams = new JSONObject(); + // 交易流水号 + reqParams.put("req_seq_id", refundOrder.getRefundOrderId()); + // 原交易请求订单号 + reqParams.put("org_req_seq_id", payOrder.getPayOrderId()); + // 商户号 + reqParams.put("huifu_id", payOrder.getChannelMchNo()) + ; + reqParams.put("notify_url", getNotifyUrl()); + // 请求日期 + reqParams.put("req_date", DateUtil.format(refundOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 退款金额 + reqParams.put("ord_amt", AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount())); + // 原交易请求日期 + reqParams.put("org_req_date", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/scanpay/refund", refundOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + // 调用成功 + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String tradeState = resData.getString("trans_stat"); + if (DgPayKit.STATE_SUCCESS_S.equals(tradeState)) { + String channelOrderNo = resData.getString("hf_seq_id"); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return ChannelRetMsg.confirmSuccess(channelOrderNo); + }else if (DgPayKit.STATE_FAIL_F.equals(tradeState)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + // 状态失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + } + }else if (DgPayKit.STATE_ING.equals(code)){ + return channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + // 状态失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + } + return channelRetMsg; + } + + private ChannelRetMsg autoPosRefund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + + // 智能POS bizParams参数 + JSONObject bizParams = JSONObject.parseObject(payOrder.getChannelBizData()); + if (bizParams == null || StringUtils.isBlank(bizParams.getString("deviceNo"))) { + throw new BizException("该订单不支持接口退款,请在POS机完成退款!"); + } + + try { + + // 请求数据data + JSONObject dataParams = new JSONObject(); + dataParams.put("device_id", bizParams.getString("deviceNo")); + + // 退款信息 + JSONObject jsonData = new JSONObject(); + jsonData.put("interfaceType", "refund"); + jsonData.put("channelId", DgPayKit.covertChannelId(bizParams.getString("channelType"))); // 支付渠道 + jsonData.put("ordAmt", refundOrder.getRefundAmount().toString()); + jsonData.put("oriOutOrderId", payOrder.getPayOrderId()); // 原三方订单号 + jsonData.put("outOrdId", refundOrder.getRefundOrderId()); // 外部订单号 + jsonData.put("bgRetUrl", "virgo://" + getPosNotifyUrl()); + dataParams.put("json_data", jsonData.toJSONString()); + + JSONObject response = DgPayKit.request(mchAppConfigContext, dataParams, "/trade/cloudmis/device/information", refundOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + + String code = resData.getString("resp_code"); + if(!DgPayKit.STATE_SUCCESS.equals(code)){ + log.error("斗拱智能POS退款失败,错误码:{},错误信息:{}", code, resData.getString("resp_desc")); + } + + channelRetMsg.setChannelOrderId(resData.getString("termOrdId")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + return channelRetMsg; + + }catch (BizException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(e.getApiRes().getCode()+""); + channelRetMsg.setChannelErrMsg(e.getApiRes().getMsg()); + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + if (StringUtils.equals(refundOrder.getWayCode(), CS.PAY_WAY_CODE.AUTO_POS)) { + return ChannelRetMsg.waiting(); + } + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + DgpayIsvsubMchParams mchParams = (DgpayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getMchApplyment().getAutoConfigMchAppId(), refundOrder.getIfCode()); + JSONObject reqParams = new JSONObject(); + // 交易流水号 + reqParams.put("org_req_seq_id", refundOrder.getRefundOrderId()); + // 商户号 + reqParams.put("huifu_id", mchParams.getHuifuId()); + // 原机构请求日期 + reqParams.put("org_req_date", DateUtil.format(refundOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + JSONObject response = DgPayKit.request(mchAppConfigContext, reqParams, "/trade/payment/scanpay/refundquery", refundOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + //如果查询请求成功 + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String tradeState = resData.getString("trans_stat"); + if (DgPayKit.STATE_SUCCESS_S.equals(tradeState)) { + return ChannelRetMsg.confirmSuccess(null); + }else if (DgPayKit.STATE_FAIL_F.equals(tradeState)) { + // 失败 + return ChannelRetMsg.confirmFail(); + } + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + + private ChannelRetMsg autoPosQuery(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) { + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + + // 智能POS bizParams参数 + JSONObject bizParams = JSONObject.parseObject(refundOrder.getChannelBizData()); + if (bizParams == null) { + throw new BizException("不支持退款补单"); + } + + try { + + // 请求数据data + JSONObject dataParams = new JSONObject(); + dataParams.put("device_id", bizParams.getString("deviceNo")); + + // 退款信息 + JSONObject jsonData = new JSONObject(); + jsonData.put("interfaceType", "queryOrder"); + jsonData.put("tradeNo", refundOrder.getChannelPayOrderNo()); // 外部订单号 + jsonData.put("outOrdId", refundOrder.getPayOrderId()); // 外部订单号 + jsonData.put("isSale", "0"); + jsonData.put("channelId", DgPayKit.covertChannelId(bizParams.getString("channelType"))); + dataParams.put("json_data ", jsonData.toJSONString()); + + JSONObject response = DgPayKit.request(mchAppConfigContext, dataParams, "/trade/cloudmis/device/information", refundOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + + String code = resData.getString("resp_code"); + if(!DgPayKit.STATE_SUCCESS.equals(code)){ + log.error("斗拱智能POS退款查单失败,错误码:{},错误信息:{}", code, resData.getString("resp_desc")); + } + + return channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }catch (BizException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(e.getApiRes().getCode()+""); + channelRetMsg.setChannelErrMsg(e.getApiRes().getMsg()); + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return channelRetMsg; + } + + /** + * 退款权限 + * @param settleType + * @param applyId + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliBar.java new file mode 100644 index 0000000..9554d62 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliBar.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 斗拱 支付宝 条码支付 +* +* @author pangxiaoyu +* +* @date 2021/6/8 18:11 +*/ +@Slf4j +@Service("dgpayPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("auth_code", bizRQ.getAuthCode()); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/micropay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String transStat = resData.getString("trans_stat"); + String channelOrderNo = resData.get("hf_seq_id").toString(); + String debit_type = resData.getString("debit_type"); + if(StringUtils.isEmpty(debit_type) || "0".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + }else if("D".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.DEBIT.getType()); + }else if("C".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.CREDIT.getType()); + }else{ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + } + channelRetMsg.setChannelOrderId(channelOrderNo); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + // 交易状态成功 + channelRetMsg.setPlatformOrderNo(resData.get("out_trans_id").toString()); + channelRetMsg.setPlatformMchOrderNo(resData.get("party_order_id").toString()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + res.setPayData(resData.toString()); + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + // 交易状态失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + } + + } else if (DgPayKit.STATE_ING.equals(code)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + } else{ + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliJsapi.java new file mode 100644 index 0000000..604596b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliJsapi.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 支付宝 jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:20 + */ +@Slf4j +@Service("dgpayPaymentByAliJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "A_JSAPI"); + + JSONObject aliJson = new JSONObject(); + aliJson.put("buyer_id", bizRQ.getBuyerUserId()); + dataParams.put("alipay_data", aliJson.toJSONString()); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if(DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + JSONObject aliResJson = resData.getJSONObject("pay_info"); + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + String tradeNo = aliResJson.getString("tradeNO"); + res.setAlipayTradeNo(tradeNo); + res.setPayData(JSON.toJSONString(new ChannelJsapiMsg(tradeNo))); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { //其他状态, 表示下单失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliLite.java new file mode 100644 index 0000000..7ce70cf --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliLite.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 支付宝小程序 + * + * @author xiaoyu + * + * @date 2023/1/6 16:53 + */ +@Slf4j +@Service("dgpayPaymentByAliLiteService") //Service Name需保持全局唯一性 +public class AliLite extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if (StringUtils.isEmpty(bizRQ.getBuyerUserId())) { + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + // 构造函数响应数据 + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "A_JSAPI"); + + JSONObject aliJson = new JSONObject(); + aliJson.put("buyer_id", bizRQ.getBuyerUserId()); + dataParams.put("alipay_data", aliJson.toJSONString()); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if(DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + JSONObject aliResJson = resData.getJSONObject("pay_info"); + String tradeNo = aliResJson.getString("tradeNO"); + res.setAlipayTradeNo(tradeNo); + res.setPayData(JSON.toJSONString(new ChannelJsapiMsg(tradeNo))); + // 支付中 + channelRetMsg.setChannelOrderId(channelOrderNo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + }else { + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliQr.java new file mode 100644 index 0000000..abcfb9f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AliQr.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/** + * 斗拱 支付宝扫码 + * + * @author xiaoyu + * + * @date 2022/5/24 17:38 + */ +@Service("dgpayPaymentByAliQrService") //Service Name需保持全局唯一性 +public class AliQr extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliQrOrderRQ aliQrOrderRQ = (AliQrOrderRQ)rq; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + // 构造函数响应数据 + AliQrOrderRS res = ApiResBuilder.buildSuccess(AliQrOrderRS.class); + res.setChannelRetMsg(channelRetMsg); + + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "A_NATIVE"); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if (DgPayKit.STATE_ING.equals(code)) { + + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + String qrCdLink = resData.getString("qr_code"); + channelRetMsg.setChannelOrderId(channelOrderNo); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(aliQrOrderRQ.getPayDataType())){ //二维码地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + }else{ //默认都为跳转地址方式 + jsapiMsg.setQrCodeUrl(qrCdLink); + res.setCodeUrl(qrCdLink); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AutoPos.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AutoPos.java new file mode 100644 index 0000000..826bcc0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/AutoPos.java @@ -0,0 +1,94 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AutoPosOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AutoPosOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** +* 斗拱 智能POS +* +* @author zx +* +* @date 2022/8/2 18:11 +*/ +@Slf4j +@Service("dgpayPaymentByAutoPosService") //Service Name需保持全局唯一性 +public class AutoPos extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + if(StringUtils.isEmpty(payOrder.getDeviceNo())){ + throw new BizException("智能POS[deviceNo]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + String logPrefix = "【斗拱 智能POS支付】"; + AutoPosOrderRS res = ApiResBuilder.buildSuccess(AutoPosOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + AutoPosOrderRQ bizRQ = (AutoPosOrderRQ) rq; + + try { + + // 请求数据data + JSONObject dataParams = new JSONObject(); + dataParams.put("device_id", payOrder.getDeviceNo()); + + // 交易信息 + JSONObject tradeJSON = new JSONObject(); + tradeJSON.put("interfaceType", "payment"); + tradeJSON.put("channelId", DgPayKit.covertChannelId(bizRQ.getChannelType())); + tradeJSON.put("mobilePayType", DgPayKit.covertMobilePayType(bizRQ.getPayType())); + tradeJSON.put("ordAmt", payOrder.getFindAmt().toString()); + tradeJSON.put("outOrdId", payOrder.getPayOrderId()); + tradeJSON.put("goodsDesc", payOrder.getBody()); + tradeJSON.put("bgRetUrl", "virgo://" + getPosNotifyUrl()); + tradeJSON.put("ordRemark", payOrder.getSellerRemark()); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + tradeJSON.put("isDelayAcct", isDivisionOrder(payOrder) ? "1" : "0"); + } + + dataParams.put("json_data", tradeJSON.toJSONString()); + + JSONObject response = DgPayKit.request(mchAppConfigContext, dataParams, "/trade/cloudmis/device/information", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if(!DgPayKit.STATE_SUCCESS.equals(code)){ + log.error("{}推送订单失败,错误码:{},错误信息:{}", logPrefix, code, resData.getString("resp_desc")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(resData.getString("result_code")); + channelRetMsg.setChannelErrMsg(resData.getString("result_msg")); + return res; + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 调用成功,改为支付中 + + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepBar.java new file mode 100644 index 0000000..1683e0f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepBar.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 微信 条码支付 + * + * @author xiaoyu + * + * @date 2022/6/13 18:03 + */ +@Slf4j +@Service("dgpayPaymentByDcepBarService") //Service Name需保持全局唯一性 +public class DcepBar extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + DcepBarOrderRQ bizRQ = (DcepBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + DcepBarOrderRQ bizRQ = (DcepBarOrderRQ) rq; + DcepBarOrderRS res = ApiResBuilder.buildSuccess(DcepBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("auth_code", bizRQ.getAuthCode()); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/micropay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String transStat = resData.getString("trans_stat"); + String channelOrderNo = resData.get("hf_seq_id").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + // 交易状态成功 + channelRetMsg.setPlatformOrderNo(resData.get("out_trans_id").toString()); + channelRetMsg.setPlatformMchOrderNo(resData.get("party_order_id").toString()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + res.setPayData(resData.toString()); + String debit_type = resData.getString("debit_type"); + if(StringUtils.isEmpty(debit_type) || "0".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + }else if("D".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.DEBIT.getType()); + }else if("C".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.CREDIT.getType()); + }else{ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + } + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + // 交易状态失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + } + + } else if (DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + }else{ //其他状态, 表示下单失败 + + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepQr.java new file mode 100644 index 0000000..a79ab51 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/DcepQr.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/** + * 斗拱 支付宝扫码 + * + * @author xiaoyu + * + * @date 2022/5/24 17:38 + */ +@Service("dgpayPaymentByDcepQrService") //Service Name需保持全局唯一性 +public class DcepQr extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + DcepQrOrderRQ aliQrOrderRQ = (DcepQrOrderRQ)rq; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + // 构造函数响应数据 + DcepQrOrderRS res = ApiResBuilder.buildSuccess(DcepQrOrderRS.class); + res.setChannelRetMsg(channelRetMsg); + + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "D_NATIVE"); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if (DgPayKit.STATE_ING.equals(code)) { + + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + String qrCdLink = resData.getString("qr_code"); + channelRetMsg.setChannelOrderId(channelOrderNo); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(aliQrOrderRQ.getPayDataType())){ //二维码地址 + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + }else{ //默认都为跳转地址方式 + jsapiMsg.setQrCodeUrl(qrCdLink); + res.setCodeUrl(qrCdLink); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/UpQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/UpQr.java new file mode 100644 index 0000000..85482af --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/UpQr.java @@ -0,0 +1,89 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 银联扫码支付 + * + * @author zx + * + * @date 2022/06/22 20:09 + */ +@Service("dgpayPaymentByUpQrService") //Service Name需保持全局唯一性 +@Slf4j +public class UpQr extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + UpQrOrderRQ bizRQ = (UpQrOrderRQ)rq; + // 构造函数响应数据 + UpQrOrderRS res = ApiResBuilder.buildSuccess(UpQrOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + try { + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "U_NATIVE"); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if (DgPayKit.STATE_ING.equals(code)) { + + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + String qrCdLink = resData.getString("qr_code"); + channelRetMsg.setChannelOrderId(channelOrderNo); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + }else{ //默认都为跳转地址方式 + res.setCodeUrl(qrCdLink); + jsapiMsg.setQrCodeUrl(qrCdLink); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxBar.java new file mode 100644 index 0000000..a0463a9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxBar.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 微信 条码支付 + * + * @author xiaoyu + * + * @date 2022/6/13 18:03 + */ +@Slf4j +@Service("dgPaymentByWxBarService") //Service Name需保持全局唯一性 +public class WxBar extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("auth_code", bizRQ.getAuthCode()); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/micropay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if(DgPayKit.STATE_SUCCESS.equals(code)){ + String transStat = resData.getString("trans_stat"); + String channelOrderNo = resData.get("hf_seq_id").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + if (DgPayKit.STATE_SUCCESS_S.equals(transStat)) { + // 交易状态成功 + channelRetMsg.setPlatformOrderNo(resData.get("out_trans_id").toString()); + channelRetMsg.setPlatformMchOrderNo(resData.get("party_order_id").toString()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + res.setPayData(resData.toString()); + String debit_type = resData.getString("debit_type"); + if(StringUtils.isEmpty(debit_type) || "0".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + }else if("D".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.DEBIT.getType()); + }else if("C".equals(debit_type)){ + channelRetMsg.setDrType(CS.DrType.CREDIT.getType()); + }else{ + channelRetMsg.setDrType(CS.DrType.OTHER.getType()); + } + }else if (DgPayKit.STATE_FAIL_F.equals(transStat)) { + // 交易状态失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + } + + } else if (DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + }else{ //其他状态, 表示下单失败 + + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxJsapi.java new file mode 100644 index 0000000..b498f86 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxJsapi.java @@ -0,0 +1,98 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:40 + */ +@Slf4j +@Service("dgpayPaymentByWxJsapiService") //Service Name需保持全局唯一性 +public class WxJsapi extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params)configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + + // 设置请求参数 + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "T_JSAPI"); + JSONObject wxJson = new JSONObject(); +// wxJson.put("sub_appid", oauth2Params.getAppId()); + wxJson.put("openid", bizRQ.getChannelUserId()); + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + wxJson.put("sub_appid", bizRQ.getSubAppid()); + }else{ + wxJson.put("sub_appid", oauth2Params.getAppId()); + } + dataParams.put("wx_data", wxJson.toJSONString()); + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("resp_code"); + channelRetMsg.setChannelBizData(resData); + if(DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + String payInfo = resData.getString("pay_info"); + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + res.setPayInfo(payInfo); + res.setPayData(payInfo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { //其他状态, 表示下单失败 + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxLite.java new file mode 100644 index 0000000..678626a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/WxLite.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:52 + */ +@Slf4j +@Service("dgpayPaymentByWxLiteService") //Service Name需保持全局唯一性 +public class WxLite extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + + // 设置请求参数 + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "T_MINIAPP"); + + JSONObject wxJson = new JSONObject(); + wxJson.put("sub_appid", oauth2Params.getLiteAppId()); + wxJson.put("sub_openid", bizRQ.getChannelUserId()); + + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + wxJson.put("sub_appid", bizRQ.getSubAppid()); + } + dataParams.put("wx_data", wxJson.toJSONString()); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if(DgPayKit.STATE_ING.equals(code)){ + String channelOrderNo = resData.get("hf_seq_id").toString(); + //付款信息 + String payInfo = resData.getString("pay_info"); + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + res.setPayInfo(payInfo); + res.setPayData(payInfo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + }else { //其他状态, 表示下单失败 + + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + }catch (Exception e) { + log.error(e.getMessage()); + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/YsfJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/YsfJsapi.java new file mode 100644 index 0000000..7648801 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/payway/YsfJsapi.java @@ -0,0 +1,93 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgPayKit; +import com.jeequan.jeepay.thirdparty.channel.dgpay.DgpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 银联 jsapi + * + * @author zx + * + * @date 2021/6/8 18:11 + */ +@Slf4j +@Service("dgpayPaymentByYsfJsapiService") //Service Name需保持全局唯一性 +public class YsfJsapi extends DgpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getUserId())){ + throw new BizException("[userId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + try { + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + JSONObject dataParams = DgPayKit.dataParams(payOrder, getNotifyUrl()); + dataParams.put("trade_type", "U_JSAPI"); + + JSONObject jsapiJson = new JSONObject(); + jsapiJson.put("customer_ip", payOrder.getClientIp()); + jsapiJson.put("user_id", bizRQ.getUserId()); + dataParams.put("unionpay_data", jsapiJson.toJSONString()); + + // 设置订单是否需要分账 + if(isDivisionOrder(payOrder)) { + dataParams.put("delay_acct_flag", "Y"); + } + + JSONObject response = DgPayKit.payRequest(mchAppConfigContext, dataParams, "/trade/payment/jspay", payOrder.getIfCode()); + JSONObject resData = response.getJSONObject("data"); + channelRetMsg.setChannelBizData(resData); + String code = resData.getString("resp_code"); + if (DgPayKit.STATE_ING.equals(code)) { + String channelOrderNo = resData.getString("hf_seq_id"); + //付款信息 + String payInfo = resData.getString("pay_info"); + channelRetMsg.setChannelOrderId(channelOrderNo); + res.setRedirectUrl(payInfo); + ChannelJsapiMsg channelJsapiMsg = new ChannelJsapiMsg(); + channelJsapiMsg.setRedirectUrl(payInfo); + res.setPayData(JSON.toJSONString(channelJsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { + DgPayKit.channelMsgError(resData, channelRetMsg); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return res; + + }catch (Exception e) { + log.error(e.getMessage()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg("系统异常"); + return res; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/DgUtils.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/DgUtils.java new file mode 100644 index 0000000..10b090b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/DgUtils.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DgUtils { + + private static List> limitList = new ArrayList<>(); + + static { + Map item = new HashMap<>(); + item.put("name", "贵州省"); + item.put("code", "520000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "湖南省"); + item.put("code", "430000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "陕西省"); + item.put("code", "610000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "河南省"); + item.put("code", "410000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "浙江省"); + item.put("code", "330000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "重庆市"); + item.put("code", "500100"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "云南省"); + item.put("code", "530000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "湖北省"); + item.put("code", "420000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "福建省"); + item.put("code", "350000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "宁夏回族自治区"); + item.put("code", "640000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "吉林省"); + item.put("code", "220000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "黑龙江省"); + item.put("code", "230000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "江苏省"); + item.put("code", "320000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "海南省"); + item.put("code", "460000"); + limitList.add(item); + + item = new HashMap<>(); + item.put("name", "青海省"); + item.put("code", "630000"); + limitList.add(item); + } + + /** + * 检验银联限制 + * @param provinceCode + * @return + */ + public static boolean checkBankLimitArea(String provinceCode) { + for (Map item : limitList) { + if (provinceCode.equals(item.get("code"))) { + return false; + } + } + + return true; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/MD5Utils.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/MD5Utils.java new file mode 100644 index 0000000..53714f5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/dgpay/utils/MD5Utils.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.channel.dgpay.utils; + +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; + +/** + * @ClassName MD5Utils + * @Description + * @Author boy + * @Date 2019/8/30 8:29 PM + */ +public class MD5Utils { + static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + static String MD5 = "MD5";//加签方式:MD5 + + /* + * @Author boy + * @Description 数据签名 + * @Date 2019/8/31 1:57 PM + * @Param [data, key] + * @return java.lang.String + */ + public static String sign(String data, String key) throws Exception { + //得到明文的字节数组 + byte[] btInput = (data + key).getBytes(); + // 创建一个提供信息摘要算法的对象(MD5摘要算法) + MessageDigest messageDigest = MessageDigest.getInstance(MD5); + // 使用指定的字节更新摘要 + messageDigest.update(btInput); + // 得到二进制的密文 + byte[] encryptData = messageDigest.digest(); + // 把密文转换成十六进制的字符串形式 + String encryptDataStr = bytesToHex(encryptData); + return encryptDataStr; + + } + + /* + * @Author boy + * @Description 验签 + * @Date 2019/8/31 1:57 PM + * @Param [data, key, sign][明文数据,签名key,接收到的签名] + * @return boolean + */ + public static boolean verifySign(String data, String key, String sign) throws Exception { + //调用加签方法,看加签后的签名是否和接收到的一致 + String encryptData = sign(data, key); + if (encryptData.equals(sign)) { + return true; + } else { + return false; + } + } + + /* + * @Author boy + * @Description 将byte数组转化为16进制字符串 + * @Date 2019/8/31 1:58 PM + * @Param [bytes] + * @return java.lang.String + */ + public static String bytesToHex(byte[] bytes) { + int k = 0; + char[] hexChars = new char[bytes.length * 2]; + for (int i = 0; i < bytes.length; i++) { + byte byte0 = bytes[i]; + hexChars[k++] = hexDigits[byte0 >>> 4 & 0xf]; + hexChars[k++] = hexDigits[byte0 & 0xf]; + } + return new String(hexChars); + } + + + public static void main(String[] args) throws Exception { + Map hashMap = new HashMap<>(); + String data = "你好!MD你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!你好!MD5!5!"; + String key = "1234567890abcdef";//密钥 + String dataSign = MD5Utils.sign(data, key); + hashMap.put("data", data); + hashMap.put("dataSign", dataSign); + System.out.println("明文:" + hashMap.get("data")); + System.out.println("签名:" + hashMap.get("dataSign")); + System.out.println("验签结果:" + MD5Utils.verifySign(data, key, dataSign)); + } +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlKit.java new file mode 100644 index 0000000..f9a857a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlKit.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay; + +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.DBPaymentConfig; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.thirdparty.channel.flpay.model.ReqEntity; +import com.jeequan.jeepay.thirdparty.channel.flpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.flpay.model.RespEntity; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.xml.bind.DatatypeConverter; +import java.nio.charset.StandardCharsets; + +/** + * TODO + * 福禄打款 + * @author crystal + * @date 2024/3/25 11:09 + */ +@Slf4j +public class FlKit { + + /** + * 发起请求 + * @param method + * @param config + * @param bizData + * @return + */ + public static JSONObject reqApi(ReqMethod.Method method, DBPaymentConfig config, JSONObject bizData) { + ReqEntity reqEntity = initSign(config,bizData); + String url = ReqMethod.getUrl(config,method); + log.info("【福禄】请求参数:{}",JSON.toJSONString(reqEntity)); + HttpResponse response = HttpRequest.post(url).body(JSON.toJSONString(reqEntity)).execute(); + if(!response.isOk()){ + throw ChannelException.sysError("付款接口请求异常"); + } + log.info("【福禄】返回参数:{}",response.body()); + RespEntity respEntity = JSON.parseObject(response.body(), RespEntity.class); + return initResult(respEntity); + } + + /** + * 公共返回参数处理 + * @param resp + * @return + */ + public static JSONObject initResult(RespEntity resp) { + if(!resp.isSuccess()){ + String msg = StringUtils.isNotEmpty(resp.getMsg()) ? resp.getMsg() : resp.getSubMsg(); + throw ChannelException.sysError(msg); + } + return JSON.parseObject(resp.getData()); + } + + public static ReqEntity initSign(DBPaymentConfig config,JSONObject bizData){ + bizData.put("taskNo", config.getTaskNo()); + bizData.put("appId", config.getAppId()); + ReqEntity reqEntity = new ReqEntity(config.getAppId(),bizData); + reqEntity.setSign(genSign(reqEntity,config)); + return reqEntity; + } + + /** + * 校验回调签名 + * @param reqEntity + * @param config + * @return + */ + public static boolean checkResultNotify(ReqEntity reqEntity, DBPaymentConfig config) { + String sign = genSign(reqEntity,config); + return !sign.equalsIgnoreCase(reqEntity.getSign()); + } + + private static String genSign(ReqEntity reqEntity,DBPaymentConfig config) { + String signStr = JeepayKit.getStrSort(reqEntity.toMap()); + //前5位 + String prefix = config.getSecret().substring(0,5); + //后5位 + String suffix = config.getSecret().substring(config.getSecret().length() - 5); + //拼接在首尾 + String signContent = prefix + signStr + suffix; + try { + String signText = DigestUtil.sha256Hex(signContent); + byte[] secretSigning = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, config.getSecret().getBytes(StandardCharsets.UTF_8)).digest(reqEntity.getTimestamp()); + String sign = DatatypeConverter.printHexBinary(DigestUtil.hmac(HmacAlgorithm.HmacSHA256,secretSigning).digest(signText)).toLowerCase(); + return sign; + } catch (Exception e) { + throw new BizException("生成签名异常"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayApiService.java new file mode 100644 index 0000000..c12ca78 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayApiService.java @@ -0,0 +1,173 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.CashoutRecord; +import com.jeequan.jeepay.core.exception.ChannelException; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.AccountFundInfo; +import com.jeequan.jeepay.db.entity.AccountInfo; +import com.jeequan.jeepay.service.impl.AccountInfoService; +import com.jeequan.jeepay.thirdparty.channel.flpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.AbstractRepayApiService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Locale; + +/** + * TODO + * 福禄打款 + * @author crystal + * @date 2024/3/25 10:38 + */ +@Service +@Slf4j +public class FlpayRepayApiService extends AbstractRepayApiService { + + @Autowired + private AccountInfoService accountInfoService; + + @Override + public String getIfCode() { + return CS.IF_CODE.FLPAY; + } + + /** + * 是否需要签约 + * @return + */ + @Override + public boolean isSign() { + return true; + } + + @Override + public void preCheck(String mchNo,byte accountType,Long changeAmt) { + this.checkAccountBalance(mchNo,accountType,changeAmt); + } + + /** + * 查询账户余额 + * @param mchNo 用户号 + * @param accountType 账户类型 + * @return + */ + @Override + public Account queryAccountBalance(String mchNo, byte accountType) { + AccountInfo accountInfo = accountInfoService.getAccountInfo(mchNo, accountType); + return new Account(accountInfo.getBalacne(),accountInfo.getFreeze()); + } + + /** + * 签约正常 签约状态(0-待处理 1-校验失败 2-待签约 3-签约成功 4-校验错误) + * @param sign + * @param config + * @return + */ + @Override + public ChannelRetMsg sign(PaymentSign sign, DBPaymentConfig config) { + JSONObject bizData = new JSONObject(); + bizData.put("userName",sign.getUserName()); + bizData.put("idCard",sign.getIdCard().toUpperCase(Locale.ROOT)); + bizData.put("mobile",sign.getMobile()); + JSONObject respBizData = FlKit.reqApi(ReqMethod.Method.SIGN, config, bizData); + Integer signStatus = respBizData.getInteger("signStatus"); + switch (signStatus){ + case 3: + return ChannelRetMsg.confirmSuccess(respBizData.getString("peopleId")); + } + return ChannelRetMsg.confirmFail(null,respBizData.getString("failReason")); + } + + /** + * 签约结果查询 + * @param sign + * @param config + * @return + */ + @Override + public ChannelRetMsg querySign(PaymentSign sign, DBPaymentConfig config) { + JSONObject bizData = new JSONObject(); + bizData.put("userName",sign.getUserName()); + bizData.put("idCard",sign.getIdCard().toUpperCase(Locale.ROOT)); + JSONObject respBizData = FlKit.reqApi(ReqMethod.Method.SIGN_QUERY, config, bizData); + Integer signStatus = respBizData.getInteger("signStatus"); + switch (signStatus){ + case 3: + return ChannelRetMsg.confirmSuccess(respBizData.getString("peopleId")); + } + return ChannelRetMsg.confirmFail(null,respBizData.getString("failReason")); + } + + /** + * 付款 + * @return + */ + @Override + public ChannelRetMsg payment(CashoutRecord record,DBPaymentConfig config) { + JSONObject bizData = new JSONObject(); + bizData.put("accountNumber",record.getSettAccountNo()); + bizData.put("afterTaxAmount", AmountUtil.convertCent2Dollar(AmountUtil.abs(record.getSettAmount()))); + String grantType = AccountFundInfo.WECHAT.equals(record.getSettAccountType()) ? "微信支付" : AccountFundInfo.ALIPAY == record.getSettAccountType() ? "支付宝" : "银行卡"; + bizData.put("grantType", grantType); + bizData.put("idCard",record.getIdCard()); + bizData.put("outBizNo",record.getTransferOrderId()); + bizData.put("mobile",record.getBankPhone()); + bizData.put("transRemark","账户结算处理"); + bizData.put("remark",record.getAuditRemark()); + bizData.put("userName",record.getSettAccountName()); + bizData.put("notifyUrl",getNotifyUrl()); + try { + JSONObject respBizData = FlKit.reqApi(ReqMethod.Method.PAYMENT, config, bizData); + ChannelRetMsg channelRetMsg = ChannelRetMsg.waiting(); + channelRetMsg.setChannelOrderId(respBizData.getString("bizNo")); + channelRetMsg.setChannelBizData(respBizData); + return channelRetMsg; + }catch (ChannelException e){ + throw ChannelException.sysError(e.getMessage()); + }catch (Exception e){ + return ChannelRetMsg.confirmFail(e.getMessage()); + } + } + + /** + * 付款结果查询 + * @param outBizNo 外部请求流水号 + * @param config + * @return + */ + @Override + public ChannelRetMsg queryPayment(String outBizNo, DBPaymentConfig config) { + JSONObject bizData = new JSONObject(); + bizData.put("outBizNo",outBizNo); + try { + JSONObject respBizData = FlKit.reqApi(ReqMethod.Method.PAYMENT_QUERY, config, bizData); + String failCause = respBizData.getString("failCause"); + Integer auditStatus = respBizData.getInteger("auditStatus"); + Integer payStatus = respBizData.getInteger("payStatus"); + String payFailCause = respBizData.getString("payFailCause"); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + retMsg.setChannelErrMsg(failCause); + switch (auditStatus){ + case 2: + return retMsg; + } + retMsg.setChannelErrMsg(payFailCause); + switch (payStatus){ + case 3: + return ChannelRetMsg.confirmSuccess(respBizData.getString("bizNo")); + } + return retMsg; + }catch (ChannelException e){ + throw ChannelException.sysError(e.getMessage()); + }catch (Exception e){ + return ChannelRetMsg.confirmFail(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayNoticeService.java new file mode 100644 index 0000000..1e541b3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/FlpayRepayNoticeService.java @@ -0,0 +1,115 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.interfaces.paychannel.IRepayNoticeService; +import com.jeequan.jeepay.core.model.DBPaymentConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.db.entity.AccountChangeInfo; +import com.jeequan.jeepay.service.impl.AccountChangeInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.AbstractRepayNoticeService; +import com.jeequan.jeepay.thirdparty.channel.flpay.model.ReqEntity; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * TODO + * + * @author crystal + * @date 2024/3/27 10:43 + */ +@Service +@Slf4j +public class FlpayRepayNoticeService extends AbstractRepayNoticeService { + + @Autowired private SysConfigService sysConfigService; + + @Override + public String getIfCode() { + return CS.IF_CODE.FLPAY; + } + + /** + * 参数解析 + * @param request + * @param urlOrderId + * @return + */ + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId) { + JSONObject reqParamJSON = getReqParamJSON(); + JSONObject bizContent = reqParamJSON.getJSONObject("bizContent"); + return MutablePair.of(bizContent.getString("bizOutNo"), reqParamJSON); + } + + /** + * + * @param request + * @param urlOrderId + * @param params + * @return + */ + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, String urlOrderId, Object params) { + JSONObject respJson = (JSONObject) JSON.toJSON(params); + boolean verifyResult = verifyParams(respJson); + if(!verifyResult){ + throw ResponseException.buildText("sign check error"); + } + JSONObject biz = respJson.getJSONObject("bizContent"); + String channelRemark = "【渠道备注】"; + log.info("【灵工】打款状态回调,打款流水号:{},业务参数:{}", urlOrderId, biz); + //失败原因 + String failCause = biz.getString("failCause"); + //审核状态 审核状态 0-待审核 1-审核通过 2-人工审核拒绝 + int auditStatus = biz.getIntValue("auditStatus"); + //发放状态 发放(推送)状态 0-待发放 1-发放通过 2-发放拒绝 + int grantStatus = biz.getIntValue("grantStatus"); + //支付状态 0-未处理 1-待打款 2-打款中 3-打款成功 4-打款失败 5-退票退款 + int payStatus = biz.getIntValue("payStatus"); + //支付失败原因 + String payFailCause = biz.getString("payFailCause"); + String bizNo = biz.getString("bizNo"); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + ResponseEntity okResponse = textResp("success"); + retMsg.setResponseEntity(okResponse); + retMsg.setChannelOrderId(bizNo); + retMsg.setChannelErrMsg(channelRemark + failCause); + if(grantStatus == 2 || auditStatus == 2){ + return retMsg; + } + retMsg.setChannelErrMsg(channelRemark + payFailCause); + switch (payStatus){ + case 3: + return ChannelRetMsg.confirmSuccess(bizNo); + } + return retMsg; + } + + /** + * 校验参数 + * @param noticeData + * @return + */ + public boolean verifyParams(JSONObject noticeData) { + DBPaymentConfig config = sysConfigService.getDbPaymentConfig(); + if(CS.IF_CODE.FLPAY.equals(config.getPaymentType())){ + try { + return FlKit.checkResultNotify(noticeData.toJavaObject(ReqEntity.class),config); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } + return true; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqEntity.java new file mode 100644 index 0000000..7aa0f77 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqEntity.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay.model; + + +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashMap; +import java.util.Map; + +/** + * TODO + * 福禄公共参数请求封装 + * @author crystal + * @date 2024/2/29 11:53 + */ +@Setter +@Getter +public class ReqEntity { + + + /** + *appid + */ + private String appId; + + /** + * 时间戳 + */ + private String timestamp; + + /** + * 随机字符串 + */ + private String nonce; + + /** + * 请求唯一表示,代表订单号 长度不能超过12 + */ + private String sign; + + /** + * 请求回调地址 + */ + private String bizContent; + + + public ReqEntity(String appId, JSONObject bizData) { + this.appId = appId; + this.nonce = RandomUtil.randomString(20); + if(bizData != null){ + this.bizContent = bizData.toJSONString(); + }else{ + this.bizContent = "{}"; + } + String timestamp = System.currentTimeMillis() + ""; + this.timestamp = timestamp; + } + + public Map toMap() { + Map params = new HashMap<>(5); + params.put("appId",this.appId); + params.put("timestamp",this.timestamp); + params.put("nonce",this.nonce); + params.put("bizContent",this.bizContent); + return params; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqMethod.java new file mode 100644 index 0000000..f707c1a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/ReqMethod.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay.model; + +import com.jeequan.jeepay.core.model.DBPaymentConfig; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2024/3/25 11:40 + */ +@Data +public class ReqMethod { + + @Getter + @AllArgsConstructor + public enum Method{ + + SIGN("/api/open/uploadPeople","自由职业者签约"), + + SIGN_QUERY("/api/open/queryPeople","自由职业者签约状态查询"), + + PAYMENT("/api/open/uploadPlan","付款接口"), + + ACCOUNT_QUERY("/api/open/queryPayMethod","账户类型查询接口"), + + AUDIT("/api/open/grantPlan","审核下发结算"), + + PAYMENT_QUERY("/api/open/queryPlan","结算发放结果查询接口"), + + ; + private final String method; + + private final String desc; + + } + + + /** 获取请求接口地址 + * @param method + * @return + */ + public static String getUrl(DBPaymentConfig config,Method method){ + return config.getDomain() + method.getMethod(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/RespEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/RespEntity.java new file mode 100644 index 0000000..938b2c9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/flpay/model/RespEntity.java @@ -0,0 +1,48 @@ +package com.jeequan.jeepay.thirdparty.channel.flpay.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * 福禄通用返回参数封装 + * @author crystal + * @date 2024/3/25 13:51 + */ +@Data +@NoArgsConstructor +public class RespEntity { + + public static final int SUCCESS_CODE = 0; + + public static final int SUCCESS_EXT_CODE = 1; + + public static final int NETWORK_ERROR_CODE = 500; + + private int code; + + private String data; + + private String msg; + + private String subCode; + + private String subMsg; + + public RespEntity(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public static RespEntity fail(String msg) { + RespEntity result = new RespEntity(NETWORK_ERROR_CODE,msg); + return result; + } + + /** + * 判断是否返回成功 + */ + public boolean isSuccess(){ + return SUCCESS_CODE == this.code; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/DgpayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/DgpayGetApplymentDataService.java new file mode 100644 index 0000000..8719120 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/DgpayGetApplymentDataService.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.db.entity.BankBranch; +import com.jeequan.jeepay.service.impl.BankBranchService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service("dgpayGetApplymentDataService") +@Slf4j +public class DgpayGetApplymentDataService implements IGetApplymentDataService { + + @Autowired + private BankBranchService bankBranchService; + + @Override + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { +// Assert.notBlank(bankName, "银行名称不能为空"); + Page page = new Page<>(); + bankBranchService.pageByArea(page, cityCode, bankName, branchName); + + return page.getRecords().stream().map( t -> ((JSONObject) JSON.toJSON(t))).collect(Collectors.toList()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelNoticeService.java new file mode 100644 index 0000000..ffea623 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelNoticeService.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayOrderStatus; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 快钱支付 回调接口实现类 + * + * @author xiaoyu + * + * @date 2022/4/15 10:23 + */ +@Service +@Slf4j +public class KqpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.KQPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + JSONObject reqParamJSON = getReqParamJSON(); + JSONObject notifyHead = reqParamJSON.getJSONObject("head"); + return MutablePair.of(notifyHead.getString("externalRefNumber"), reqParamJSON); + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + JSONObject respJson = (JSONObject) JSON.toJSON(params); + log.info("快钱回调参数:{}",respJson); + boolean verifyResult = verifyParams(respJson, mchAppConfigContext); + log.info("快前参数解密结果:{}",respJson); + // 验证参数失败 + if(!verifyResult){ + throw ResponseException.buildText("签名校验失败"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(KqpayKit.resSuccess(respJson)); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); + JSONObject requestBody = respJson.getJSONObject("requestBody"); + KqpayOrderStatus orderStatus = KqpayOrderStatus.getVal(requestBody.getString("orderStatus")); + result.setChannelOrderId(requestBody.getString("idOrderCtrl")); + result.setPlatformMchOrderNo(requestBody.getString("idTxnCtrl")); + result.setChannelErrCode(requestBody.getString("bizResponseCode")); + result.setChannelErrMsg(requestBody.getString("bizResponseMessage")); + JSONObject equityInfo = requestBody.getJSONObject("equityInfo"); + result.setPlatformOrderNo(requestBody.getString("channelTradeNo")); + result.setChannelUserId(requestBody.getString("thirdPartyBuyerId")); + switch (orderStatus){ + case SUCCESS: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + } + return result; + } + + + /** + * 验证银盛支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + return KqpayKit.checkResultNotify(jsonParams,mchAppConfigContext); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelRefundNoticeService.java new file mode 100644 index 0000000..8c3af7c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayChannelRefundNoticeService.java @@ -0,0 +1,102 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayOrderStatus; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 拉卡拉退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class KqpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.KQPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject reqParamJSON = getReqParamJSON(); + JSONObject notifyHead = reqParamJSON.getJSONObject("head"); + return MutablePair.of(notifyHead.getString("externalRefNumber"), reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + String logPrefix = "【处理快钱退款回调】"; + try { + JSONObject respJson = (JSONObject) JSON.toJSON(params); + log.info("快钱回调参数:{}",respJson); + boolean verifyResult = verifyParams(respJson, mchAppConfigContext); + // 验证参数失败 + if(!verifyResult){ + throw ResponseException.buildText("签名校验失败"); + } + log.info("快前参数解密结果:{}",respJson); + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(KqpayKit.resSuccess(respJson)); + ChannelRetMsg result = new ChannelRetMsg(); + //验签成功后判断上游订单状态 + result.setResponseEntity(okResponse); + JSONObject requestBody = respJson.getJSONObject("requestBody"); + KqpayOrderStatus orderStatus = KqpayOrderStatus.getVal(requestBody.getString("orderStatus")); + result.setChannelOrderId(requestBody.getString("idOrderCtrl")); + result.setPlatformMchOrderNo(requestBody.getString("idTxnCtrl")); + result.setChannelErrCode(requestBody.getString("bizResponseCode")); + result.setChannelErrMsg(requestBody.getString("bizResponseMessage")); + result.setPlatformOrderNo(requestBody.getString("channelTradeNo")); + result.setChannelUserId(requestBody.getString("thirdPartyBuyerId")); + switch (orderStatus){ + case SUCCESS: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + default: + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + break; + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * 验证快钱退款通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + return KqpayKit.checkResultNotify(jsonParams,mchAppConfigContext); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayGetApplymentDataService.java new file mode 100644 index 0000000..36a063f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayGetApplymentDataService.java @@ -0,0 +1,43 @@ + +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.db.entity.BankBranch; +import com.jeequan.jeepay.service.impl.BankBranchService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/*** +* +* @author zx +* +* @date 2022/1/4 14:54 +*/ +@Service +@Slf4j +public class KqpayGetApplymentDataService implements IGetApplymentDataService { + + @Autowired + private BankBranchService bankBranchService; + + /** + * @cityCode 这里取城市名称. + */ + @Override + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { +// Assert.notBlank(bankName, "银行名称不能为空"); + Page page = new Page<>(); + bankBranchService.pageByArea(page, cityCode, bankName, branchName); + + return page.getRecords().stream().map( t -> ((JSONObject) JSON.toJSON(t))).collect(Collectors.toList()); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..a41793a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchAlipayConfigService.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class KqpayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + // 进件商户信息 +// JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); +// if (suJson == null || StringUtils.isEmpty(suJson.getString("huifuId"))) { +// result.setState("查询失败"); +// result.setErrInfo("商户参数为空,该商户还未进件成功"); +// return result; +// } + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + // 服务商配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode()); + // 渠道拓展地址 + result.setSignUrl(isvParams.getAliChannelExtUrl()); + // 图片类型 + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + result.setState("当前通道无法确定认证状态"); + + String succResParameter = mchApplyment.getSuccResParameter(); + JSONObject succRes = JSON.parseObject(succResParameter); + JSONArray alipayList = succRes.getJSONArray("alipayList"); + if (alipayList.isEmpty()) { + result.setState("未报备"); + } else { + JSONObject aliReportData = alipayList.getJSONObject(0); + String subMchId = aliReportData.getString("subMchId"); + if (ObjectUtils.isEmpty(subMchId)) { + result.setChannelSubMchId(aliReportData.getString("errorMsg")); + } else { + result.setChannelSubMchId(subMchId); + } + } + + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..f988eb9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchApplymentNotifyService.java @@ -0,0 +1,160 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.db.entity.PayInterfaceConfig; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.PayInterfaceConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +@Slf4j +@Service("kqpayIsvmchApplymentNotifyService") +public class KqpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private KqpayMchApplymentService kqpayMchApplymentService; + + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + + @Autowired @Lazy + private MchApplymentService mchApplymentService; + + @Autowired + protected RequestKitBean requestKitBean; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public ResponseEntity retOk(Object params) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + String s = KqpayKit.resSuccess((reqParamJSON)); + return ResponseEntity.ok(JSON.parseObject(s)); + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + String url = "https://reg.shouyinbeipay.com/auditCallback/kq"; + HttpResponse execute = null; + try { + execute = HttpRequest.post(url) + .body(reqParamJSON.toJSONString()) + .execute(); + if (execute.isOk()) { + log.info("回调给{}成功", url); + } else { + log.info("回调给{}异常", url); + } + } catch (Exception e) { + log.info("回调给{}异常", url); + if (execute != null) { + execute.close(); + } + } + + + + String orderId = reqParamJSON.getJSONObject("head").getString("externalRefNumber"); + com.jeequan.jeepay.db.entity.MchApplyment mchApplyment = mchApplymentService.getByOrderId(orderId); + + String memberCode = reqParamJSON.getJSONObject("head").getString("memberCode"); + + QueryWrapper qWrapper = Wrappers.query(); + qWrapper.eq("if_params->>'$.memberCode'", memberCode); + qWrapper.eq("if_code", "kqpay"); + + List list = payInterfaceConfigService.list(qWrapper); + + if (list.isEmpty()) { + throw new BizException("没找到配置信息"); + } + + KqpayIsvParams isvParams = JSON.parseObject(list.get(0).getIfParams(), KqpayIsvParams.class); + + log.info("快钱回调: {}", reqParamJSON); + + KqpayKit.checkResultNotify(reqParamJSON, isvParams); + + return new MutablePair<>(mchApplyment.getApplyId(), reqParamJSON); + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment) { + MchApplyment resultMch = new MchApplyment(); + + JSONObject bizParam = ((JSONObject) params).getJSONObject("requestBody"); + String status = bizParam.getString("status"); + + JSONObject openResult = bizParam.getJSONObject("openResult"); + + JSONObject param = new JSONObject(); + param.put("isReceived", "1"); + + ResponseEntity ok = ResponseEntity.ok(param); + + String comments = bizParam.getString("comments"); + resultMch.setApplyErrorInfo(comments); + if ("REJECTED".equals(status)) { + resultMch.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return new MutablePair<>(resultMch, ok); + } + + if ("FINISHED".equals(status)) { + resultMch.setChannelMchNo(bizParam.getString("subMerchantId")); + resultMch.setSuccResParameter(bizParam.toString()); + // 收集子商户信息 + kqpayMchApplymentService.subMchColl(mchApplyment, bizParam); + return new MutablePair<>(resultMch, ok); + } + + if ("TO_BE_SIGNED".equals(status) ) { + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + int allowSignResult = kqpayMchApplymentService.isAllowSign(mchApplyment); + if (allowSignResult == 2) { + resultMch.setState(MchApplyment.STATE_WAIT_SIGN); + return new MutablePair<>(resultMch, ok); + } + + if (allowSignResult == 1) { + kqpayMchApplymentService.signApply(mchApplyment); + resultMch = kqpayMchApplymentService.query(mchApplyment); + return new MutablePair<>(resultMch, ok); + } + } + + if ("TO_BE_REAUDITED".equals(status)) { + if (openResult != null) { + resultMch.setChannelMchNo(openResult.getString("subMerchantId")); + resultMch.setSuccResParameter(openResult.toString()); + kqpayMchApplymentService.subMchColl(mchApplyment, openResult); + } + resultMch.setState(MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY); + + return new MutablePair<>(resultMch, ok); + } + + return new MutablePair<>(mchApplyment, ok); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..e6ca9e7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchModifyApplymentService.java @@ -0,0 +1,267 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.KqpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +@Slf4j +@Service +public class KqpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + KqpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, KqpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + KqpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, KqpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setIsUncrpSett(mchModifyData.getIllegal()); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setPersonalInformationAttorney(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + throw new BizException("暂不支持该操作"); +// MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); +// MchApplyment mchApplyment = mchDataPair.getRight(); +// +// KqpayApplymentInfo kqpayApplymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), KqpayApplymentInfo.class); +// +// JSONObject param = new JSONObject(); +// param.fluentPut("operator", "admin") +// .fluentPut("subBillAccount", kqpayApplymentInfo.getContactEmail()); +// +// // 套餐信息 +// JSONObject packageInfo = new JSONObject(); +// param.put("packageInfo", packageInfo); +// packageInfo.put("packageCode", KqpayConst.Package.COMPANY_BASE_EDIT.getCode()); +// +// String openAccountWillingnessLetter = "https://syb-jq-public.oss-cn-hangzhou.aliyuncs.com/applyment/38835122-55b6-48be-884e-35e4aa856b99.jpg"; +// +// KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); +// String openAccountWillingnessLetterFssId = KqpayKit.uploadRequest(openAccountWillingnessLetter, isvParams); +// +// List additionList = new ArrayList<>(); +// param.put("additionList", additionList); +// Map addition = new HashMap<>(); +// additionList.add(addition); +// addition.put("additionFssId", openAccountWillingnessLetterFssId); +// addition.put("additionFileType", "OPEN_ACCOUNT_WILLINGNESS_LETTER"); +// addition.put("additionRemark", "开户意愿确认函"); +// addition.put("extName", "jpg"); +// +// KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS005, isvParams, param); +// +// return mchDataPair; + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + resultModifyApplyment.setModifyApplyId(modifyApplyment.getModifyApplyId()); + MchApplyment mchApplyment = mchDataPair.getRight(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + KqpayApplymentInfo kqpayApplymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), KqpayApplymentInfo.class); + + MchModifyApplymentModel modifyApplyBiz = JSON.parseObject(modifyApplyment.getApplyDetailInfo(), MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.fluentPut("operator", "admin") + .fluentPut("subBillAccount", kqpayApplymentInfo.getContactEmail()); + + // 套餐信息 + JSONObject packageInfo = new JSONObject(); + param.put("packageInfo", packageInfo); + packageInfo.put("packageCode", KqpayConst.Package.COMPANY_BASE_EDIT.getCode()); + + JSONObject packageParam = new JSONObject(); + packageInfo.put("packageParameter", packageParam); + // 定向付款信息域 + JSONObject settlementInfo = new JSONObject(); + packageParam.put("packageParam", settlementInfo); + settlementInfo.put("bankMobilePhone", modifyApplyBiz.getPhone()); + if (modifyApplyBiz.getSettAccountType().equals("B")) { + settlementInfo.put("accountType", "0"); + } else { + if (modifyApplyBiz.getIllegal().equals("Y")) { + settlementInfo.put("accountType", "2"); + } else { + settlementInfo.put("accountType", "1"); + } + } + settlementInfo.put("accountNo", modifyApplyBiz.getSettAccountNo()); + settlementInfo.put("accountName", modifyApplyBiz.getSettAccountName()); + settlementInfo.put("bankName", modifyApplyBiz.getSettAccountBankName()); + settlementInfo.put("bankBranch", modifyApplyBiz.getSettAccountBankBranchName()); + Assert.notNull(modifyApplyBiz.getSettAccountBankBranchAreaCode(), "支行地区编码信息不能为空"); + Assert.isTrue(modifyApplyBiz.getSettAccountBankBranchAreaCode().size() >= 2, "支行地区编码信息不能为空"); + settlementInfo.put("areaCode", modifyApplyBiz.getSettAccountBankBranchAreaCode().getString(1)); + + if (kqpayApplymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + JSONObject accOpenInfo = new JSONObject(); + packageParam.put("accOpenInfo", accOpenInfo); + String accOpenFssId = KqpayKit.uploadRequest(modifyApplyBiz.getAccOpenCertImg(), isvParams); + } + + if (modifyApplyBiz.getIllegal().equals("Y")) { + JSONObject authorizerInfo = new JSONObject(); + packageParam.put("authorizerInfo", authorizerInfo); + String authFssId = KqpayKit.uploadRequest(modifyApplyBiz.getNonLegSettleAuthPic(), isvParams); + authorizerInfo.put("authFssId", authFssId); + String idCard1Img = KqpayKit.uploadRequest(modifyApplyBiz.getSettAccountIdcard1Img(), isvParams); + authorizerInfo.put("authNationalFssId", idCard1Img); + String idCard2Img = KqpayKit.uploadRequest(modifyApplyBiz.getSettAccountIdcard2Img(), isvParams); + authorizerInfo.put("authPersonFssId", idCard2Img); + authorizerInfo.put("beginDate", modifyApplyBiz.getSettAccountIdcardEffectBegin()); + authorizerInfo.put("expireDate", modifyApplyBiz.getSettAccountIdcardEffectEnd()); + authorizerInfo.put("authIdCard", modifyApplyBiz.getSettAccountIdcardNo()); + authorizerInfo.put("authTel", modifyApplyBiz.getPhone()); + authorizerInfo.put("authName", modifyApplyBiz.getSettAccountName()); + String authHandFssId = KqpayKit.uploadRequest(modifyApplyBiz.getAuthHandImg(), isvParams); + authorizerInfo.put("authHandFssId", authHandFssId); + } + + try { + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS005, isvParams, param); + JSONObject responseBody = kqpayResp.getResponseBody(); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + + resultModifyApplyment.setChannelVar1(responseBody.toJSONString()); + + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + resultModifyApplyment.setApplyDetailInfo("[" + bizResponseMessage + "]"); + + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return new MutablePair<>(resultModifyApplyment, null); + } + + String orderId = responseBody.getString("orderId"); + resultModifyApplyment.setChannelApplyNo(orderId); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + return new MutablePair<>(resultModifyApplyment, null); + + } catch (Exception e) { + resultModifyApplyment.setApplyDetailInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultMchModifyApplyment = mchDataPair.left; + MchApplyment resultMch = mchDataPair.right; + + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchDataPair.right); + + JSONObject reqParam = new JSONObject(); + reqParam.put("orderId", resultMchModifyApplyment.getChannelApplyNo()); + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS002, isvParams, reqParam); + JSONObject responseBody = kqpayResp.getResponseBody(); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + + + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + log.info("快钱查询商户变更审核状态失败, {}", bizResponseMessage); + + return new MutablePair<>(); + } + + String status = responseBody.getString("status"); + + if ("FINISHED".equals(status)) { + return localModifySettlement(mchDataPair); + } + + return new MutablePair<>(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchWxConfigService.java new file mode 100644 index 0000000..26083d3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayIsvmchWxConfigService.java @@ -0,0 +1,89 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class KqpayIsvmchWxConfigService implements IIsvmchWxConfigService { + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + KqpayIsvParams isvParams = (KqpayIsvParams)configContextQueryService.queryIsvParams(mchApplyment); + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxOpenUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + result.setState("当前通道无法确定认证状态"); + result.setErrInfo(""); + + String succResParameter = mchApplyment.getSuccResParameter(); + JSONObject succRes = JSON.parseObject(succResParameter); + JSONArray alipayList = succRes.getJSONArray("wechatList"); + if (alipayList.isEmpty()) { + result.setState("未报备"); + } else { + JSONObject aliReportData = alipayList.getJSONObject(0); + String subMchId = aliReportData.getString("subMchId"); + if (ObjectUtils.isEmpty(subMchId)) { + result.setErrInfo(aliReportData.getString("errorMsg")); + } else { + result.setChannelSubMchId(subMchId); + } + } + + return result; + } + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayKit.java new file mode 100644 index 0000000..19851ee --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayKit.java @@ -0,0 +1,303 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.bill99.crypto.entity.Bill99CertConfig; +import com.bill99.crypto.service.CryptoService; +import com.bill99.crypto.service.processor.P7CryptoServiceProcessor; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayReqHead; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.HttpClientCert; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.HttpsClientFactory; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.util.Assert; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; + +/** + * 快钱请求参数 + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class KqpayKit { + + private static final CryptoService cryptoService = P7CryptoServiceProcessor.getInstance(); + + /** + * 快钱入网请求网关 + */ + public static final String APPLYMENTS_GATE_WAY = KqpayConst.APPLYMENTS_GATE_WAY; + + public static final String TRADE_GATE_WAY = KqpayConst.TRADE_GATE_WAY; + + + public static String getExternalRefNumber(String memberCode) { + return memberCode + DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); + } + + public static String uploadRequest(String imgUrl, KqpayIsvParams isvParams) { + byte[] imgFileByteArray = HttpUtil.downloadBytes(imgUrl); + String base64 = Base64.encode(imgFileByteArray); + + JSONObject reqParam = new JSONObject(); + reqParam.put("fileBuffer", base64); + reqParam.put("fileName", "test.jpg"); + + return KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS000, isvParams, reqParam).getResponseBody().getString("fssId"); + } + + public static KqpayResp applymentRequest(KqpayConst.ReqMethod reqMethod, KqpayIsvParams isvParams, JSONObject bizContent) { + String externalRefNumber = ((String) bizContent.remove("externalRefNumber")); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取快钱入网配置信息"); + + KqpayReqHead head = init(reqMethod, isvParams, externalRefNumber); + head.setVendorMemberCode(null); + try { + return reqApi(APPLYMENTS_GATE_WAY, head, bizContent, isvParams); + } catch (Exception e) { + log.info("快钱入网请求异常,", e); + throw new BizException("快钱入网请求异常, " + e.getMessage()); + } + } + + /** + * 初始化 + * + * @return + */ + public static KqpayReqHead init(KqpayConst.ReqMethod reqMethod, KqpayIsvParams isvParams, String outFlowNo) { + initCert(isvParams); + KqpayReqHead head = new KqpayReqHead(); + head.setVersion("1.0.0"); + head.setVendorMemberCode(isvParams.getVendorMemberCode()); + head.setMemberCode(head.getVendorMemberCode()); + head.setMessageType(reqMethod.getMessageType()); + if (StringUtils.isNotEmpty(outFlowNo)) { + head.setExternalRefNumber(outFlowNo); + } else { + head.setExternalRefNumber(getExternalRefNumber(isvParams.getVendorMemberCode())); + } + return head; + } + + + public static KqpayResp payRequest(KqpayConst.ReqMethod reqMethod, MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String outFlowNo) {// 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取快钱入网配置信息"); + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.KQPAY); + + KqpayReqHead head = init(reqMethod, isvParams, outFlowNo); + head.setMemberCode(bizContent.getString("kqCode")); + try { + return reqApi(TRADE_GATE_WAY, head, bizContent, isvParams); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 设置参数 + * + * @param mchAppConfigContext + * @param bizContent + */ + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent) { + KqpayIsvsubMchParams mchParams = JSON.parseObject(mchAppConfigContext.getMchApplyment().getSuccResParameter(),KqpayIsvsubMchParams.class); + bizContent.put("merchantId", mchParams.getSubMerchantId()); + List terminalInfos = mchParams.getTerminalInfos(); + JSONObject item = terminalInfos.stream().filter(e -> "terminalQkf".equals(e.getString("type"))).findFirst().orElse(new JSONObject()); + JSONArray terminalIds = item.getJSONArray("terminalIds"); + bizContent.put("terminalId", terminalIds.get(0)); + bizContent.put("kqCode", mchParams.getSubMemberCode()); + bizContent.put("cur", "CNY"); + } + + public static KqpayResp reqApi(String url, KqpayReqHead head, JSONObject bizData, KqpayIsvParams isvParams) throws Exception { + JSONObject encryptBody = null; + try { + encryptBody = cryptoService.seal(bizData.toString()); + } catch (Exception e) { + log.error("请求快钱,加密加签出错。", e); + } + JSONObject requestString = new JSONObject(); + requestString.put("head", head); + requestString.put("requestBody", encryptBody); + log.info("快钱接口请求地址:{}", url); + log.info("快钱接口请求业务参数:{}", bizData); + log.info("快钱接口请求参数:{}", requestString); + @Cleanup CloseableHttpClient httpClient = url.startsWith("https") ? createHttpsClient(isvParams) : HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000) + .setConnectTimeout(10000).build(); + httpPost.setConfig(requestConfig); + httpPost.setEntity(new StringEntity(requestString.toJSONString(), Consts.UTF_8)); + return httpClient.execute(httpPost, httpresponse -> { + int statusCode = httpresponse.getStatusLine().getStatusCode(); + if (200 != statusCode) { + return null; + } else { + String entityStr; + HttpEntity entity = httpresponse.getEntity(); + if (null != entity) { + entityStr = EntityUtils.toString(entity, Consts.UTF_8); + log.info("快钱请求返回待解密报文:{}", entityStr); + JSONObject respEncryptObject = JSON.parseObject(entityStr); + JSONObject respHead = respEncryptObject.getJSONObject("head"); + JSONObject respEncryptBody = respEncryptObject.getJSONObject("responseBody"); + String respSignedData = respEncryptBody.getString("signedData"); + String respEnvelopedData = respEncryptBody.getString("envelopedData"); + KqpayResp kqpayResp = new KqpayResp(respHead); + if (KqpayConst.SUCCESS.equals(respHead.getString("responseCode"))) { + String respDecryptBody = null; + try { + respDecryptBody = cryptoService.unSeal(respEnvelopedData, respSignedData); + log.info("快钱请求返回报文:{}", respDecryptBody); + } catch (Exception e) { + log.info("快钱入网解密异常", e); + } + kqpayResp.setResponseBody(JSON.parseObject(respDecryptBody)); + return kqpayResp; + } else { + log.error("请求快钱出错, head报错信息 = {}", respHead.toJSONString()); + throw new BizException(respHead.getString("responseTextMessage")); + } + } else { + throw new BizException("接口请求异常"); + } + } + }); + } + + private static CloseableHttpClient createHttpsClient(KqpayIsvParams kqpayIsvParams) throws Exception { + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(kqpayIsvParams.getSslPublicPath()); + + @Cleanup InputStream keystoreFileInputStream = new FileInputStream(certFilePath); + + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(keystoreFileInputStream, kqpayIsvParams.getStorePwd().toCharArray()); + HttpClientCert httpClientCert = new HttpClientCert(); + httpClientCert.setKeyStore(keyStore); + httpClientCert.setKeyStorePwd(kqpayIsvParams.getStorePwd()); + httpClientCert.setConnTimeout(60000); + httpClientCert.setSoTimeout(10000); + httpClientCert.setSSLVersion("TLSv1.2"); + HttpsClientFactory factory = new HttpsClientFactory(); + return factory.createSSLClient(httpClientCert); + } + + + /** + * 解析异步通知参数 + * + * @param resNotify + * @return + */ + public static boolean checkResultNotify(JSONObject resNotify, KqpayIsvParams isvParams) { + try { + initCert(isvParams); + JSONObject requestBody = resNotify.getJSONObject("requestBody"); + String signedData = requestBody.getString("signedData"); + String envelopedData = requestBody.getString("envelopedData"); + String data = cryptoService.unSeal(envelopedData, signedData); + resNotify.put("requestBody", JSON.parseObject(data)); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 解析异步通知参数 + * + * @param resNotify + * @return + */ + public static boolean checkResultNotify(JSONObject resNotify, MchAppConfigContext mchAppConfigContext) { + try { + initCert(mchAppConfigContext); + JSONObject requestBody = resNotify.getJSONObject("requestBody"); + String signedData = requestBody.getString("signedData"); + String envelopedData = requestBody.getString("envelopedData"); + String data = cryptoService.unSeal(envelopedData, signedData); + resNotify.put("requestBody", JSON.parseObject(data)); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 组装快钱异步通知返回参数 + * + * @param notifyParams + * @return + */ + public static String resSuccess(JSONObject notifyParams) { + JSONObject responseBody = new JSONObject(1); + responseBody.put("isReceived", "1"); + try { + JSONObject respEncryptBody = cryptoService.seal(responseBody.toJSONString()); + JSONObject respMessage = new JSONObject(); + respMessage.put("head", notifyParams.getJSONObject("head")); + respMessage.put("responseBody", respEncryptBody); + return StringEscapeUtils.unescapeJson(respMessage.toJSONString()); + } catch (Exception e) { + e.printStackTrace(); + } + return "error"; + } + + public static KqpayIsvParams initCert(MchAppConfigContext configContext) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取快钱入网配置信息"); + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(configContext.getMchApplyment().getIsvNo(), CS.IF_CODE.KQPAY); + return initCert(isvParams); + } + + public static KqpayIsvParams initCert(KqpayIsvParams isvParams) { + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + Assert.notNull(channelCertConfigKitBean, "无法获取快钱入网配置文件"); + String bill99DefaultPublicPath = channelCertConfigKitBean.getCertFilePath(isvParams.getBill99DefaultPublicPath()); + String merchantDefaultPrivatePath = channelCertConfigKitBean.getCertFilePath(isvParams.getMerchantDefaultPrivatePath()); + + Bill99CertConfig bill99CertConfig = new Bill99CertConfig(); + bill99CertConfig.setBill99DefaultPublicPath(bill99DefaultPublicPath); + bill99CertConfig.setMerchantDefaultPrivatePassword(isvParams.getMerchantDefaultPrivatePassword()); + bill99CertConfig.setMerchantDefaultPrivatePath(merchantDefaultPrivatePath); + cryptoService.setBill99CertConfig(bill99CertConfig); + return isvParams; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApiService.java new file mode 100644 index 0000000..dd059b5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApiService.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +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 com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO + * + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class KqpayMchApiService extends AbstractMchApiService { + + + @Override + public String getIfCode() { + return CS.IF_CODE.KQPAY; + } + + /** + * 是否支持当前接口 false 不支持 + * @return + */ + @Override + public boolean preCheck() { + return false; + } + + /** + * + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + throw new BizException("快钱通道暂不支持线上操作方式,请联系客服报备处理"); + } + + /** + * 结算记录查询 + * @param settleRq + * @param isvNo + * @param isvParams + * @return + */ + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, IsvParams isvParams) { + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApplymentService.java new file mode 100644 index 0000000..decad71 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayMchApplymentService.java @@ -0,0 +1,772 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.KqpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.concurrent.Future; +import java.util.function.Consumer; + +/** + * 快钱商户入网审批流程 + * 调用BS008,获取个人信息同意授权书等官方电子版数据 + * 新商户进件申请成功,此时调BS002,返的是 审批中 , + * 审批完成后查询到的是 合同待签约(不能直接签约,需要激活快钱,签约前可以调合同查询接口,如果是0-待签约 才能调签约接口) + * 签约完成后,调BS002 返的是 已完成,至此进件完成 + */ +@Service +@Slf4j +public class KqpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + /** + * 开户意愿确认, 入网前的操作 + * + * @param mchApplyment + */ + public void willingnessConfirm(MchApplyment mchApplyment, KqpayApplymentInfo applymentInfo, KqpayIsvParams isvParams) { + JSONObject bizContent = new JSONObject(); + bizContent.put("legalId", applymentInfo.getIdcardNo()); + bizContent.put("legalName", applymentInfo.getIdcardName()); + + if (applymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + // 营业执照信息 + bizContent.put("businessLicense", applymentInfo.getLicenseNo()); + bizContent.put("merchantType", "1"); + + if (applymentInfo.getIsUncrpSett().equals("Y")) { + bizContent.put("settleToAuth", "1"); + bizContent.put("authName", applymentInfo.getSettAccountName()); + bizContent.put("authIdCard", applymentInfo.getSettAccountIdcardNo()); + } + } else { + bizContent.put("merchantType", "2"); + } + + bizContent.put("merchantName", applymentInfo.getMchFullName()); + + List fileTypeList = new ArrayList<>(); + bizContent.put("fileTypeList", fileTypeList); + fileTypeList.add("OPEN_ACCOUNT_WILLINGNESS_LETTER"); + fileTypeList.add("SPE_MERCH_SQSDZRGZS"); + fileTypeList.add("PERSONAL_INFORMATION_ATTORNEY"); + + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS008, isvParams, bizContent); + JSONObject responseBody = kqpayResp.getResponseBody(); + + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + log.info("快钱开户意愿确认接口调用失败, {}", bizResponseMessage); + throw new BizException("快钱开户意愿确认失败, " + bizResponseMessage); + } + + JSONArray data = responseBody.getJSONArray("data"); + mchApplyment.setChannelVar1(data.toJSONString()); + } + + /** + * 上传图片,入网时候 + * + * @param uploadResultMap 上传图片返回结果 + * @param imgUrl 图片链接 + * @param isvParams 通道服务商配置参数 + */ + public void uploadRequest(Map> uploadResultMap, String key, String imgUrl, KqpayIsvParams isvParams, Consumer consumer) { + // 下载文件 + if (ObjectUtils.isEmpty(imgUrl)) { + return; + } + + // 改为同步请求 + String fssId = KqpayKit.uploadRequest(imgUrl, isvParams); + consumer.accept(fssId); + +// Future submit = executorService.submit(() -> { +// String fssId = KqpayKit.uploadRequest(imgUrl, isvParams); +// consumer.accept(fssId); +// return fssId; +// }); +// +// uploadResultMap.put(key, submit); + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment firstApplyment(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + // 直接丢到异步处理进件逻辑 + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING_WAIT); + mchApplyment.setRemainStep((byte) 1); + mchApplyment.setSettlementType(CS.SETTLEMENT_TYPE.T1); + + return mchApplyment; + } + + + public JSONObject getApplymentParams(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, KqpayIsvParams isvParams) { + + String applyDetailInfo = mchApplyment.getApplyDetailInfo(); + + Map> uploadResultMap = new HashMap<>(); + + log.info("商户信息: {}", applyDetailInfo); + if (applyDetailInfo == null || applyDetailInfo.isEmpty()) { + throw new BizException("无法获取到商户信息"); + } + + KqpayApplymentInfo mchInfoSrc = JSON.parseObject(applyDetailInfo, KqpayApplymentInfo.class); + + willingnessConfirm(mchApplyment, mchInfoSrc, isvParams); + + JSONObject mchInfoDes = new JSONObject(); + mchInfoDes.put("operator", "admin"); + Assert.notNull(mchInfoSrc.getContactEmail(), "缺少电子邮箱"); + mchInfoDes.put("subBillAccount", mchInfoSrc.getContactEmail()); + // 结算信息 + mchInfoDes.put("settlementInfo", getSettlement(uploadResultMap, mchInfoSrc, isvParams)); + + // 主体信息 + JSONObject subjectInfo = getSubjectInfo(uploadResultMap, mchInfoSrc, isvParams); + + mchInfoDes.put("subjectInfo", subjectInfo); + + // 经营信息 + mchInfoDes.put("storeInfo", getStoreInfo(uploadResultMap, mchInfoSrc, isvParams)); + + // 套餐信息 + mchInfoDes.put("packageInfo", getPackageInfo(mchInfoSrc, mchApplyment)); + + List additionList = new ArrayList<>(); + mchInfoDes.put("additionList", additionList); + + JSONArray jsonArray = JSON.parseArray(mchApplyment.getChannelVar1()); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject item = jsonArray.getJSONObject(i); + String fileName = item.getString("fileName"); + String fssId = item.getString("fssId"); + String fileType = item.getString("fileType"); + + JSONObject finalAddition = new JSONObject(); + finalAddition.put("additionFssId", fssId); + finalAddition.put("additionFileType", fileType); + finalAddition.put("additionRemark", fileName); + finalAddition.put("extName", "jpg"); + additionList.add(finalAddition); + } + + // 开户意愿函走电子协议 +// if (!ObjectUtils.isEmpty(mchInfoSrc.getOpenAccountWillingnessLetter())) { +// JSONObject finalAddition = new JSONObject(); +// uploadRequest(uploadResultMap, "OPEN_ACCOUNT_WILLINGNESS_LETTER", mchInfoSrc.getOpenAccountWillingnessLetter(), isvParams, s -> { +// finalAddition.put("additionFssId", s); +// }); +// finalAddition.put("additionFileType", "OPEN_ACCOUNT_WILLINGNESS_LETTER"); +// finalAddition.put("additionRemark", "开户意愿确认函"); +// finalAddition.put("extName", "jpg"); +// additionList.add(finalAddition); +// } + // 电子协议 +// if ("C".equals(mchInfoSrc.getSettAccountType())) { +// // 个人信息单独同意授权书 +// JSONObject finalAddition2 = new JSONObject(); +// uploadRequest(uploadResultMap, "PERSONAL_INFORMATION_ATTORNEY", mchInfoSrc.getPersonalInformationAttorney(), isvParams, s -> { +// finalAddition2.put("additionFssId", s); +// }); +// finalAddition2.put("additionFileType", "PERSONAL_INFORMATION_ATTORNEY"); +// finalAddition2.put("additionRemark", "个人信息单独同意授权书"); +// finalAddition2.put("extName", "jpg"); +// additionList.add(finalAddition2); +// } + +// uploadResultMap.forEach((key, value) -> { +// try { +// value.get(); +// } catch (InterruptedException | ExecutionException e) { +// log.info("上传图片异常", e); +// throw new BizException("上传图片异常"); +// } +// }); + + return mchInfoDes; + } + + /** + * 主体信息 + */ + private JSONObject getSubjectInfo(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject subjectInfo = new JSONObject(); + + subjectInfo.put("merchantShortName", mchInfoSrc.getMchShortName()); + if (mchInfoSrc.getMerchantType() == 1) { + subjectInfo.put("subjectType", "0"); + } else if (mchInfoSrc.getMerchantType() == 2) { + subjectInfo.put("subjectType", "5"); + } else { + subjectInfo.put("subjectType", "1"); + } + + // 主体信息——营业执照信息 + if (mchInfoSrc.getMerchantType() != com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_PERSONAL) { + subjectInfo.put("businessLicenseInfo", getBusinessLicenseInfo(uploadResultMap, mchInfoSrc, isvParams)); + } + + if (com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_ENTERPRISE == mchInfoSrc.getMerchantType()) { + subjectInfo.put("accOpenInfo", getAccOpenInfo(uploadResultMap, mchInfoSrc, isvParams)); + } + + // 法人信息 + subjectInfo.put("identityInfo", getIdentityInfo(uploadResultMap, mchInfoSrc, isvParams)); + return subjectInfo; + } + + private JSONObject getAccOpenInfo(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject accOpenInfo = new JSONObject(); + + Assert.notEmpty(mchInfoSrc.getCompanyAccountLicenseImg(), "对公结算, 开户许可证不能为空"); + // 开户凭证 + uploadRequest(uploadResultMap, "accOpenFssId", mchInfoSrc.getCompanyAccountLicenseImg(), isvParams, s -> accOpenInfo.put("accOpenFssId", s)); + accOpenInfo.put("accOpenCode", mchInfoSrc.getAccOpenCode()); + accOpenInfo.put("accOpenPeriodBegin", mchInfoSrc.getAccOpenPeriodBegin()); + accOpenInfo.put("accOpenPeriodEnd", mchInfoSrc.getAccOpenPeriodEnd()); + return accOpenInfo; + } + + private JSONObject getBusinessLicenseInfo(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject businessLicenseInfo = new JSONObject(); + businessLicenseInfo.put("businessRegno", mchInfoSrc.getLicenseNo()); + businessLicenseInfo.put("merchantName", mchInfoSrc.getMchFullName()); + businessLicenseInfo.put("legalName", mchInfoSrc.getIdcardName()); + uploadRequest(uploadResultMap, "fssId", mchInfoSrc.getLicenseImg(), isvParams, s -> businessLicenseInfo.put("fssId", s)); + businessLicenseInfo.put("constraintBusiness", mchInfoSrc.getLicenseScope()); + businessLicenseInfo.put("areaCode", mchInfoSrc.getAreaCode().getString(2)); + businessLicenseInfo.put("address", mchInfoSrc.getLicenseAddress()); + businessLicenseInfo.put("handleDate", mchInfoSrc.getLicenseEffectBegin()); + if (ApplymentBasicInfo.DATE_FOREVER_VAL.equals(mchInfoSrc.getLicenseEffectEnd())) { + businessLicenseInfo.put("cancelDate", "9999-12-31"); + } else { + businessLicenseInfo.put("cancelDate", mchInfoSrc.getLicenseEffectEnd()); + } + return businessLicenseInfo; + } + + /** + * 经营信息 + */ + private JSONObject getStoreInfo(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject storeInfo = new JSONObject(); + + storeInfo.put("storeName", mchInfoSrc.getMchFullName()); + storeInfo.put("areaCode", mchInfoSrc.getAreaCode().getString(2)); + storeInfo.put("address", mchInfoSrc.getAddress()); + storeInfo.put("outStoreName", mchInfoSrc.getMchShortName()); + + // 经营图片 + uploadRequest(uploadResultMap, "headFssId", mchInfoSrc.getStoreOuterImg(), isvParams, s -> storeInfo.put("headFssId", s)); + + uploadRequest(uploadResultMap, "cashierFssId", mchInfoSrc.getStoreCashierImg(), isvParams, s -> storeInfo.put("cashierFssId", s)); + + uploadRequest(uploadResultMap, "inDoorFssId", mchInfoSrc.getStoreInnerImg(), isvParams, s -> storeInfo.put("inDoorFssId", s)); + +// String cashierFssId = uploadRequest(mchInfoSrc.getStoreOuterImg(), mchApplyment.getIsvNo()); +// storeInfo.put("headFssId", cashierFssId); +// String cashierFssId = uploadRequest(mchInfoSrc.getStoreCashierImg(), mchApplyment.getIsvNo()); +// storeInfo.put("cashierFssId", cashierFssId); +// String inDoorFssId = uploadRequest(mchInfoSrc.getStoreInnerImg(), mchApplyment.getIsvNo()); +// storeInfo.put("inDoorFssId", inDoorFssId); + return storeInfo; + } + + /** + * 法人信息 + */ + private JSONObject getIdentityInfo(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject identityInfo = new JSONObject(); + identityInfo.put("telephone", mchInfoSrc.getContactPhone()); + identityInfo.put("idType", "1"); + if (mchInfoSrc.getMerchantType() == com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_PERSONAL) { + identityInfo.put("merchantName", mchInfoSrc.getAddress() + mchInfoSrc.getIdcardName() + mchInfoSrc.getMchShortName()); + identityInfo.put("address", mchInfoSrc.getAddress()); + identityInfo.put("areaCode", mchInfoSrc.getAreaCode().getString(2)); + identityInfo.put("constraintBusiness", mchInfoSrc.getLicenseScope()); + } + + JSONObject idCardInfo = new JSONObject(); + identityInfo.put("idCardInfo", idCardInfo); + idCardInfo.put("idCardName", mchInfoSrc.getIdcardName()); + idCardInfo.put("idCardNumber", mchInfoSrc.getIdcardNo()); + idCardInfo.put("beginDate", mchInfoSrc.getIdcardEffectBegin()); + if (ApplymentBasicInfo.DATE_FOREVER_VAL.equals(mchInfoSrc.getIdcardEffectEnd())) { + idCardInfo.put("expireDate", "9999-12-31"); + } else { + idCardInfo.put("expireDate", mchInfoSrc.getIdcardEffectEnd()); + } + // 法人身份证图片 + uploadRequest(uploadResultMap, "cardPersonFssId", mchInfoSrc.getIdcard1Img(), isvParams, s -> idCardInfo.put("cardPersonFssId", s)); + + uploadRequest(uploadResultMap, "cardNationalFssId", mchInfoSrc.getIdcard2Img(), isvParams, s -> idCardInfo.put("cardNationalFssId", s)); +// String cardPersonFssId = uploadRequest(mchInfoSrc.getIdcard1Img(), mchApplyment.getIsvNo()); +// idCardInfo.put("cardPersonFssId", cardPersonFssId); +// String cardNationalFssId = uploadRequest(mchInfoSrc.getIdcard2Img(), mchApplyment.getIsvNo()); +// idCardInfo.put("cardNationalFssId", cardNationalFssId); + + if ("Y".equals(mchInfoSrc.getIsUncrpSett())) { + JSONObject authorizerInfo = new JSONObject(); + identityInfo.put("authorizerInfo", authorizerInfo); + authorizerInfo.put("authName", mchInfoSrc.getSettAccountName()); + authorizerInfo.put("authIdCard", mchInfoSrc.getSettAccountIdcardNo()); + authorizerInfo.put("beginDate", mchInfoSrc.getSettAccountIdcardEffectBegin()); + if (ApplymentBasicInfo.DATE_FOREVER_VAL.equals(mchInfoSrc.getSettAccountIdcardEffectEnd())) { + authorizerInfo.put("expireDate", "9999-12-31"); + } else { + authorizerInfo.put("expireDate", mchInfoSrc.getSettAccountIdcardEffectEnd()); + } + authorizerInfo.put("authName", mchInfoSrc.getSettAccountName()); + // 上传结算人身份证 + uploadRequest(uploadResultMap, "authPersonFssId", mchInfoSrc.getSettAccountIdcard1Img(), isvParams, s -> authorizerInfo.put("authPersonFssId", s)); + uploadRequest(uploadResultMap, "authNationalFssId", mchInfoSrc.getSettAccountIdcard2Img(), isvParams, s -> authorizerInfo.put("authNationalFssId", s)); +// String authPersonFssId = uploadRequest(mchInfoSrc.getSettAccountIdcard1Img(), mchApplyment.getIsvNo()); +// authorizerInfo.put("cardPersonFssId", authPersonFssId); +// String authNationalFssId = uploadRequest(mchInfoSrc.getSettAccountIdcard2Img(), mchApplyment.getIsvNo()); +// authorizerInfo.put("cardNationalFssId", authNationalFssId); + + authorizerInfo.put("authTel", mchInfoSrc.getBankMobile()); + // 授权证明 + uploadRequest(uploadResultMap, "authFssId", mchInfoSrc.getPersonalInformationAttorney(), isvParams, s -> authorizerInfo.put("authFssId", s)); + } + + return identityInfo; + } + + private JSONObject getSettlement(Map> uploadResultMap, KqpayApplymentInfo mchInfoSrc, KqpayIsvParams isvParams) { + JSONObject settlementInfo = new JSONObject(); + + settlementInfo.put("settlePan", mchInfoSrc.getSettAccountNo()); + settlementInfo.put("bankName", mchInfoSrc.getSettAccountBankName()); + settlementInfo.put("branchName", mchInfoSrc.getSettAccountBankBranchName()); + settlementInfo.put("areaCode", mchInfoSrc.getSettAccountBankBranchAreaCode().getString(2)); + if ("Y".equals(mchInfoSrc.getIsUncrpSett())) { + // 非法人结算 + settlementInfo.put("accountName", mchInfoSrc.getSettAccountName()); + settlementInfo.put("bankMobilePhone", mchInfoSrc.getBankMobile()); + } else { + settlementInfo.put("bankMobilePhone", mchInfoSrc.getLegalPersonPhone()); + String accountName = "C".equals(mchInfoSrc.getSettAccountType()) ? mchInfoSrc.getIdcardName() : mchInfoSrc.getMchFullName(); + settlementInfo.put("accountName", accountName); + } + + if ("C".equals(mchInfoSrc.getSettAccountType())) { + if ("Y".equals(mchInfoSrc.getIsUncrpSett())) { + // 授权人结算 + settlementInfo.put("settleAcctType", "2"); + } else { + // 法人对私结算 + settlementInfo.put("settleAcctType", "1"); + } + // 对私上传结算卡 + String cardFssId = KqpayKit.uploadRequest(mchInfoSrc.getSettAccountLicenseImg(), isvParams); + settlementInfo.put("cardFssId", cardFssId); +// uploadRequest(uploadResultMap, "cardFssId", mchInfoSrc.getSettAccountLicenseImg(), isvParams, s -> settlementInfo.put("cardFssId", s)); + } else { + // 对公,开户许可证在主体信息中已经上传 + settlementInfo.put("settleAcctType", "0"); + } + + return settlementInfo; + } + + /** + * 【微信】 + * 微信商户号ID(wechatMchID):1502807381(快钱固定值) + * 微信公众号ID(wechatAppID):wxc81c4ae33fe525f0(快钱固定值) + * 微信渠道号ID(wechatChannelID):销售前缘申请提供,示例:178354903 + * 微信关联appId(wechatSubAppId):商户微信应用id,示例:wx9a9e46c300ca733e + * 微信支付目录(wechatJsapi):商户支付目录地址,示例:https://www.99bill.com/ + * 【支付宝】 + * 支付宝APPID(aliAppID):1266000048120000 (快钱固定值) + * 支付宝PID(aliSource):2088821475893827(快钱固定值) + * 支付宝SOURCE(aliPid):2088821475893827(可以使用快钱的SOURCE或商户自己的) + */ + private JSONObject getPackageInfo(KqpayApplymentInfo kqpayApplymentInfo, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + Byte merchantType = kqpayApplymentInfo.getMerchantType(); + JSONObject packInfo = new JSONObject(); + + KqpayConst.Package usePackage = merchantType == 1 ? KqpayConst.Package.MICRO : KqpayConst.Package.COMPANY_AUTO_ACTIVATION; + packInfo.put("packageCode", usePackage.getCode()); + + JSONObject parameter = new JSONObject(); + packInfo.put("packageParameter", parameter); + parameter.put("mcc", kqpayApplymentInfo.getMccCode()); + + BigDecimal bigDecimal100 = new BigDecimal("100"); + + List paywayFeeList = kqpayApplymentInfo.getPaywayFeeList(); + if (CollUtil.isEmpty(paywayFeeList)) { + throw new BizException("缺少商户费率信息"); + } + paywayFeeList.forEach(item -> { + if (item.getWayCode().equals(CS.PAY_WAY_CODE.ALI_JSAPI)) { + parameter.put("zhifubaoRate", item.getFeeRate().multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + } + + if (item.getWayCode().equals(CS.PAY_WAY_CODE.ALI_JSAPI)) { + parameter.put("weixinRate", item.getFeeRate().multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + } + + if (item.getWayCode().equals(CS.PAY_WAY_CODE.YSF_JSAPI)) { + String feeType = item.getFeeType(); + Long maxFee = item.getMaxFee(); + // 借记卡费率上限 + parameter.put("cuDebitMaxFee", BigDecimal.valueOf(maxFee).divide(bigDecimal100, 2, RoundingMode.DOWN).stripTrailingZeros().toPlainString()); + if (PaywayFee.FEE_TYPE_LEVEL.equals(feeType)) { + // 分级 + item.getLevelList().forEach(levelItem -> { + if (Objects.equals(levelItem.getMinFee(), 100000L)) { + // 银联借记卡大额费率 + BigDecimal feeRate = levelItem.getFeeRate(); + parameter.put("cuRateDebit", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + } + }); + // 贷记卡, 不支持小微 + item.getCreditCardPaywayFee().getLevelList().forEach(levelItem -> { + BigDecimal feeRate = levelItem.getFeeRate(); + if (Objects.equals(levelItem.getMinFee(), 100000L)) { + // 银联贷记卡大额费率 + parameter.put("cuRateCredit", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + } else { + // 银联贷记卡小额费率 + parameter.put("smallDiscountRate", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + } + }); + } + } + + // 线上费率 + if (item.getWayCode().equals(CS.PAY_WAY_CODE.SCAN)) { + BigDecimal feeRate = item.getFeeRate(); + parameter.put("zhifubaoRate", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + parameter.put("weixinRate", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + + // 银联借记卡大额费率 + parameter.put("cuRateDebit", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + // 小额优惠费率 + parameter.put("smallDiscountRate", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + // + parameter.put("cuRateCredit", feeRate.multiply(bigDecimal100).stripTrailingZeros().toPlainString()); + + parameter.put("cuDebitMaxFee", "20.0"); + } + }); + + // 轻快付 + parameter.put("terminalQkf", "1"); + parameter.put("isWechatAppletPay", "1"); + + String paySiteUrl = sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + ; + if (paySiteUrl == null || paySiteUrl.isEmpty()) { + throw new BizException("未获取到支付网关信息"); + } + + // 微信配置 + WxpayOauth2Params wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchApplyment.getIsvNo(), CS.IF_CODE.WXPAY); + if (wxpayOauth2Params == null) { + throw new BizException("服务商未配置微信oauth信息"); + } + + parameter.put("wechatAppID", "wxc81c4ae33fe525f0"); + parameter.put("wechatMchID", "1502807381"); + parameter.put("wechatChannelID", "191695524"); + + String liteAppId = wxpayOauth2Params.getLiteAppId(); + if (ObjectUtils.isEmpty(liteAppId)) { + parameter.put("wechatSubAppId", wxpayOauth2Params.getAppId()); + } else { + parameter.put("wechatSubAppId", wxpayOauth2Params.getAppId() + ";" + wxpayOauth2Params.getLiteAppId()); + } + parameter.put("wechatJsapi", paySiteUrl + "/"); + + // 支付宝配置 + AlipayOauth2Params alipayOauth2Params = (AlipayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchApplyment.getIsvNo(), CS.IF_CODE.ALIPAY); + if (alipayOauth2Params == null) { + throw new BizException("服务商未配置微信oauth信息"); + } + + parameter.put("isAlipayAppletPay", "1"); + parameter.put("aliAppID", "1266000048120000"); + parameter.put("aliSource", "2088821475893827"); + parameter.put("aliPid", "2088821475893827"); + + return packInfo; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment rejectModify(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment replenishInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return null; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment query(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + log.info("快钱商户入网状态查询, 商户号为{}", mchApplyment.getApplyId()); + com.jeequan.jeepay.core.entity.MchApplyment result = new com.jeequan.jeepay.core.entity.MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + result.setState(mchApplyment.getState()); + JSONObject bizJSON = new JSONObject(); + String orderId = mchApplyment.getChannelApplyNo(); + bizJSON.put("orderId", orderId); + + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS002, isvParams, bizJSON); + JSONObject responseBody = kqpayResp.getResponseBody(); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + log.info("快钱查询商户审核状态失败, {}", bizResponseMessage); + return mchApplyment; + } + + String status = responseBody.getString("status"); + String comments = responseBody.getString("comments"); + JSONObject openResult = responseBody.getJSONObject("openResult"); + + if ("AUDITING".equals(status)) { + return result; + } + + result.setApplyErrorInfo(comments); + if ("TO_BE_SIGNED".equals(status)) { + + int allowSign = isAllowSign(mchApplyment); + // 待签约 + if (allowSign == 1) { + // 可以签约的话,直接签约之后再查询 + signApply(mchApplyment); + + return query(mchApplyment); + } + + // 待激活 + if (allowSign == 2) { + result.setState(MchApplyment.STATE_WAIT_SIGN); + return result; + } + + return result; + } + + if ("TO_BE_REAUDITED".equals(status)) { + if (openResult != null) { + result.setChannelMchNo(openResult.getString("subMerchantId")); + result.setSuccResParameter(openResult.toString()); + subMchColl(mchApplyment, openResult); + } + result.setState(MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY); + + return result; + } + + if ("REJECTED".equals(status)) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + return result; + } + + if ("FINISHED".equals(status)) { + if (openResult != null) { + result.setChannelMchNo(openResult.getString("subMerchantId")); + result.setSuccResParameter(openResult.toString()); + subMchColl(mchApplyment, openResult); + } + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS); + + return result; + } + + return result; + } + + @Override + public ApplymentSignInfo signInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + + return null; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment signApply(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String orderId = mchApplyment.getChannelVar1(); + JSONObject param = new JSONObject(); + param.put("orderId", mchApplyment.getChannelApplyNo()); + + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS004, isvParams, param); + JSONObject responseBody = kqpayResp.getResponseBody(); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + log.info("发起签约失败, {}", bizResponseMessage); + throw new BizException(bizResponseMessage); + } + + String authStatus = responseBody.getString("authStatus"); + if (!"1".equals(authStatus)) { + throw new BizException("签约失败"); + } else { + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_FINISH_SIGN); + } + + return mchApplyment; + } + + /** + * + * @param mchApplyment + * @return 返回1,可以使用接口签约,2,需要快钱官网手动签约 + */ + public int isAllowSign(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String orderId = mchApplyment.getChannelApplyNo(); + JSONObject param = new JSONObject(); + param.put("orderId", orderId); + + MchAppConfigContext mchAppConfigContext = new MchAppConfigContext(); + mchAppConfigContext.setMchType(MchInfo.TYPE_ISVSUB); + mchAppConfigContext.setMchApplyment(mchApplyment); + + KqpayIsvParams isvParams = (KqpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + KqpayResp kqpayResp = KqpayKit.applymentRequest(KqpayConst.ReqMethod.BS003, isvParams, param); + JSONObject responseBody = kqpayResp.getResponseBody(); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + + if (!KqpayConst.SUCCESS.equals(bizResponseCode)) { + // + log.info("查询签约状态失败, {}", bizResponseMessage); + return 0; + } + + JSONArray econtractList = responseBody.getJSONArray("econtractList"); + for (int i = 0; i < econtractList.size(); i++) { + JSONObject econtract = econtractList.getJSONObject(i); + + /* + * 0:待签约; + * 1:签约成功; + * 2:签约拒绝; + * 3:快钱账户待激活; + * 4:合同生成,待转 PDF; + * 6:签约中; + * 7:签约失败; + * -1:未生成合同 + */ + if (econtract.getString("authStatus").equals("0")) { + return 1; + } + + if (econtract.getString("authStatus").equals("3")) { + return 3; + } + } + + + return 0; + } + + @Override + public void subMchColl(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, Object openResult1) { + JSONObject openResult = (JSONObject) openResult1; + + String subMerchantId = openResult.getString("subMerchantId"); + List mchSubInfoEntityList = new ArrayList<>(); + + JSONArray alipayList = openResult.getJSONArray("alipayList"); + if (!CollUtil.isEmpty(alipayList)) { + getByOpenResultItem(mchApplyment.getApplyId(), subMerchantId, "ZFB", alipayList); + } + + JSONArray wechatList = openResult.getJSONArray("wechatList"); + if (!CollUtil.isEmpty(wechatList)) { + getByOpenResultItem(mchApplyment.getApplyId(), subMerchantId, "WX", wechatList); + } + + } + + public void getByOpenResultItem(String mchApplyId, String channelMchNo, String subChannelType, JSONArray subMchArr) { + List mchSubInfoEntityList = new ArrayList<>(); + for (int i = 0; i < subMchArr.size(); i++) { + JSONObject openResultItem = subMchArr.getJSONObject(i); + MchSubInfoEntity entity = new MchSubInfoEntity(); + entity.setChannelMchNo(channelMchNo); + entity.setRemark(openResultItem.getString("errorMsg")); + entity.setSubMchId(openResultItem.getString("subMchId")); + entity.setStatus(openResultItem.getString("status")); + entity.setSubMchType(subChannelType); + entity.setSubMchWay("KQ"); + entity.setMchApplyId(mchApplyId); + entity.setMainUse(1); + entity.setAuthStatus(MchSubInfo.AUTH_STATUS_UNKNOWN); + + try { + mchSubInfoService.saveBatch(mchSubInfoEntityList); + } catch (DuplicateKeyException e) { + log.info("快钱子商户信息已存在"); + } + } + } + + + @Override + public void subMchColl(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + query(mchApplyment); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPayOrderQueryService.java new file mode 100644 index 0000000..ad33d32 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPayOrderQueryService.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 查询订单 快钱支付 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class KqpayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + JSONObject bizContent = new JSONObject(); + KqpayKit.setPayParams(mchAppConfigContext,bizContent); + bizContent.put("idOrderCtrl",payOrder.getChannelOrderNo()); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7006,mchAppConfigContext,bizContent,payOrder.getPayOrderId()); + JSONObject responseBody = resp.getResponseBody(); + KqpayOrderStatus txnStatus = KqpayOrderStatus.getVal(responseBody.getString("txnStatus")); + String transNo = responseBody.getString("idOrderCtrl"); + String channelTradeNo = responseBody.getString("channelTradeNo"); + String channelSendSn = responseBody.getString("idTxnCtrl"); + String bizResponseCode = responseBody.getString("bizResponseCode"); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + ChannelRetMsg retMsg = ChannelRetMsg.confirmSuccess(transNo, channelTradeNo, channelSendSn,null); + retMsg.setChannelUserId(responseBody.getString("thirdPartyBuyerId")); + switch (txnStatus){ + case PROCESS: + return ChannelRetMsg.waiting(); + case FAIL: + return ChannelRetMsg.confirmFail(bizResponseCode,bizResponseMessage); + case CORRECT: + return ChannelRetMsg.waiting(); + default: + return retMsg; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPaymentService.java new file mode 100644 index 0000000..c850dad --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayPaymentService.java @@ -0,0 +1,104 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * TODO + * 快钱下单 + * @author crystal + * @date 2023/10/26 14:03 + */ +@Service +@Slf4j +public class KqpayPaymentService extends AbstractPaymentService { + /** + * 快钱生产环境 最少支付1元 + */ + public Long MIN_PAY_AMT = 100L; + + @Override + public String getIfCode() { + return CS.IF_CODE.KQPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + if(payOrder.getAmount() < MIN_PAY_AMT){ + throw new BizException("快钱通道最少需要支付1.00元"); + } + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + /** + * 解析公共返回参数 + * @param resp + * @param channelRetMsg + */ + public void initResult(KqpayResp resp, ChannelRetMsg channelRetMsg){ + JSONObject respBody = resp.getResponseBody(); + String bizResponseCode = respBody.getString("bizResponseCode"); + String bizResponseMessage = respBody.getString("bizResponseMessage"); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setNeedQuery(true); + channelRetMsg.setPlatformOrderNo(respBody.getString("channelTradeNo")); + channelRetMsg.setPlatformMchOrderNo(respBody.getString("idTxnCtrl")); + channelRetMsg.setChannelOrderId(respBody.getString("idOrderCtrl")); + channelRetMsg.setChannelErrCode(bizResponseCode); + channelRetMsg.setChannelErrMsg(bizResponseMessage); + channelRetMsg.setChannelUserId(respBody.getString("thirdPartyBuyerId")); + channelRetMsg.setPlatformOrderNo(respBody.getString("channelTradeNo")); + channelRetMsg.setChannelBizData(respBody); + if(!KqpayConst.BIZ_SUCCESS.equals(bizResponseCode)){ + throw new BizException(bizResponseMessage); + } + if(StringUtils.isNotEmpty(respBody.getString("txnStatus"))){ + KqpayOrderStatus txnStatus = KqpayOrderStatus.getVal(respBody.getString("txnStatus")); + switch (txnStatus){ + case SUCCESS: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setNeedQuery(true); + break; + case FAIL: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case PROCESS: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setNeedQuery(true); + break; + default: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.UNKNOWN); + channelRetMsg.setNeedQuery(true); + break; + } + } + ChannelJsapiMsg payInfo = respBody.getObject("payInfo", ChannelJsapiMsg.class); + channelRetMsg.setJsapiMsg(payInfo); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayRefundService.java new file mode 100644 index 0000000..2d98a92 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/KqpayRefundService.java @@ -0,0 +1,97 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 快钱支付 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class KqpayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.KQPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + KqpayKit.setPayParams(mchAppConfigContext,bizContent); + bizContent.put("amount",refundOrder.getRefundAmount()); + bizContent.put("origOrderCtrl",refundOrder.getChannelPayOrderNo()); + bizContent.put("origRefNumber",payOrder.getPayOrderId()); + bizContent.put("tr3Url",getNotifyUrl()); + KqpayResp kqpayResp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7003, mchAppConfigContext, bizContent, refundOrder.getRefundOrderId()); + JSONObject responseBody = kqpayResp.getResponseBody(); + channelRetMsg.setChannelOrderId(responseBody.getString("idOrderCtrl")); + channelRetMsg.setPlatformMchOrderNo(responseBody.getString("idTxnCtrl")); + channelRetMsg.setPlatformOrderNo(responseBody.getString("channelTradeNo")); + String bizResponseMessage = responseBody.getString("bizResponseMessage"); + String bizResponseCode = responseBody.getString("bizResponseCode"); + channelRetMsg.setChannelErrCode(bizResponseCode); + channelRetMsg.setChannelErrMsg(bizResponseMessage); + if(KqpayConst.SUCCESS.equals(bizResponseCode)){ + KqpayOrderStatus txnStatus = KqpayOrderStatus.getVal(responseBody.getString("txnStatus")); + switch (txnStatus){ + case FAIL: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case PROCESS: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + break; + case CORRECT: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + break; + default: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + } + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + return channelRetMsg; + } + + /** + * 是否支持平台户退款 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayOrderStatus.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayOrderStatus.java new file mode 100644 index 0000000..bd45a8b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayOrderStatus.java @@ -0,0 +1,42 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2023/11/2 18:19 + */ +@Getter +@AllArgsConstructor +public enum KqpayOrderStatus { + + SUCCESS("S","支付成功"), + + REVOKE("V","交易撤销"), + + FAIL("F","交易失败"), + + PROCESS("P","交易处理中"), + + REFUND("D","已提交收单行(退货可能返回,也表示退货成功)"), + + CORRECT("R","交易冲正"); + + private final String code; + + private final String desc; + + + public static KqpayOrderStatus getVal(String code){ + KqpayOrderStatus[] values = values(); + for (KqpayOrderStatus status:values) { + if(status.getCode().equals(code)){ + return status; + } + } + return PROCESS; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReq.java new file mode 100644 index 0000000..d58d240 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReq.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.model; + +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class KqpayReq { + + private KqpayReqHead head; + + private JSONObject requestBody; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReqHead.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReqHead.java new file mode 100644 index 0000000..aef87c1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayReqHead.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class KqpayReqHead { + + private String version; + + private String messageType; + + private String memberCode; + + private String externalRefNumber; + + private String vendorMemberCode; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayResp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayResp.java new file mode 100644 index 0000000..51d2873 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/model/KqpayResp.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.model; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class KqpayResp { + + private KqpayReqHead head; + + private JSONObject responseBody; + + public KqpayResp(JSONObject head,JSONObject responseBody) { + this.head = head.toJavaObject(KqpayReqHead.class); + this.responseBody = responseBody; + } + + public KqpayResp(JSONObject head) { + this(head,null); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliBar.java new file mode 100644 index 0000000..05a23ca --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliBar.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 支付宝 条码支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Service("kqpayPaymentByAliBarService") +public class AliBar extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + bizContent.put("cur","CNY"); + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("qrCode",bizRQ.getAuthCode()); + bizContent.put("tr3Url",getNotifyUrl()); + String expiredTime = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND) + ""; + bizContent.put("expireMinutes",expiredTime); + bizContent.put("terminalIp",payOrder.getClientIp()); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7001, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp, channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliJsapi.java new file mode 100644 index 0000000..2819c64 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliJsapi.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 斗拱 支付宝 jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:20 + */ +@Slf4j +@Service("kqpayPaymentByAliJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("userAgent","03"); + AlipayOauth2Params oauth2Params = (AlipayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + bizContent.put("subAppId",oauth2Params.getPid()); + bizContent.put("tr3Url",getNotifyUrl()); + // 买家支付宝用户ID + bizContent.put("openId", bizRQ.getBuyerUserId()); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND); + bizContent.put("txnExpireTime",between + ""); + bizContent.put("terminalIp",payOrder.getClientIp()); + bizContent.put("frontUrl",getReturnUrl(payOrder.getPayOrderId())); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7009, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp, channelRetMsg); + ChannelJsapiMsg jsapiMsg = channelRetMsg.getJsapiMsg(); + if(jsapiMsg != null ){ + // 获取payInfo + res.setAlipayTradeNo(jsapiMsg.getTradeNo()); + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliLite.java new file mode 100644 index 0000000..a2c7bbe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliLite.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 快钱 小程序支付 + * + * @author crystal + * + * @date 2021/6/8 18:08 + */ +@Service("kqpayPaymentByKqAliLiteService") //Service Name需保持全局唯一性 +@Slf4j +public class AliLite extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]参数不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("userAgent","04"); + AlipayOauth2Params oauth2Params = (AlipayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + bizContent.put("subAppId",oauth2Params.getPid()); + bizContent.put("tr3Url",getNotifyUrl()); + bizContent.put("openId", bizRQ.getBuyerUserId()); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND); + bizContent.put("txnExpireTime",between + ""); + bizContent.put("terminalIp",payOrder.getClientIp()); + bizContent.put("frontUrl",getReturnUrl(payOrder.getPayOrderId())); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7009, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp,channelRetMsg); + ChannelJsapiMsg jsapiMsg = channelRetMsg.getJsapiMsg(); + if(jsapiMsg != null ){ + // 获取payInfo + res.setAlipayTradeNo(jsapiMsg.getTradeNo()); + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliQr.java new file mode 100644 index 0000000..ded4fcf --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/AliQr.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/** + * 银盛 支付宝扫码 + * + * @author xiaoyu + * + * @date 2022/5/24 17:38 + */ +@Service("kqpayPaymentByAliQrService") //Service Name需保持全局唯一性 +public class AliQr extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliQrOrderRQ bizRQ = (AliQrOrderRQ) rq; + AliQrOrderRS res = ApiResBuilder.buildSuccess(AliQrOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + bizContent.put("cur","CNY"); + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("tr3Url",getNotifyUrl()); + String expiredTime = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND) + ""; + bizContent.put("qrCodeTimeout",expiredTime); + bizContent.put("terminalIp",payOrder.getClientIp()); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7007, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp, channelRetMsg); + String qrCode = resp.getResponseBody().getString("qrCode"); + ChannelJsapiMsg channelJsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ + channelJsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCode)); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCode)); + }else{ //默认都为跳转地址方式 + channelJsapiMsg.setQrCodeUrl(qrCode); + res.setCodeUrl(qrCode); + } + res.setPayData(JSON.toJSONString(channelJsapiMsg)); + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxBar.java new file mode 100644 index 0000000..0c9f465 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxBar.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛 微信 条码支付 + * + * @author xiaoyu + * + * @date 2022/3/10 10:04 + */ +@Slf4j +@Service("kqpayPaymentByWxBarService") +public class WxBar extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + bizContent.put("cur","CNY"); + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("qrCode",bizRQ.getAuthCode()); + bizContent.put("tr3Url",getNotifyUrl()); + String expiredTime = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND) + ""; + bizContent.put("expireMinutes",expiredTime); + bizContent.put("terminalIp",payOrder.getClientIp()); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7001, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp,channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxJsapi.java new file mode 100644 index 0000000..6bd6061 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxJsapi.java @@ -0,0 +1,83 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 快钱 微信jsapi + * + * @author crystal + * + * @date 2022/6/13 17:40 + */ +@Slf4j +@Service("kqpayPaymentByWxJsapiService") +public class WxJsapi extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openid]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("userAgent","02"); + bizContent.put("subAppId",bizRQ.getSubAppid()); + bizContent.put("tr3Url",getNotifyUrl()); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + bizContent.put("subAppId",bizRQ.getSubAppid()); + }else{ + bizContent.put("subAppId",oauth2Params.getAppId()); + } + bizContent.put("openId", bizRQ.getOpenid()); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND); + bizContent.put("txnExpireTime",between + ""); + bizContent.put("terminalIp",payOrder.getClientIp()); + bizContent.put("frontUrl",getReturnUrl(payOrder.getPayOrderId())); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7009, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp,channelRetMsg); + ChannelJsapiMsg jsapiMsg = channelRetMsg.getJsapiMsg(); + if(jsapiMsg != null ){ + String payInfo = JSON.toJSONString(jsapiMsg); + res.setPayInfo(payInfo); + res.setPayData(payInfo); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxLite.java new file mode 100644 index 0000000..af610bc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/payway/WxLite.java @@ -0,0 +1,83 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.model.KqpayResp; +import com.jeequan.jeepay.thirdparty.channel.kqpay.util.KqpayConst; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 快钱 小程序支付 + * + * @author crystal + * + * @date 2021/6/8 18:08 + */ +@Service("kqpayPaymentByKqWxLiteService") //Service Name需保持全局唯一性 +@Slf4j +public class WxLite extends KqpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openid]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + KqpayKit.setPayParams(mchAppConfigContext, bizContent); + bizContent.put("amount",payOrder.getFindAmt()); + bizContent.put("userAgent","01"); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + bizContent.put("subAppId",bizRQ.getSubAppid()); + }else{ + bizContent.put("subAppId",oauth2Params.getLiteAppId()); + } + bizContent.put("tr3Url",getNotifyUrl()); + bizContent.put("openId", bizRQ.getOpenid()); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.SECOND); + bizContent.put("txnExpireTime",between + ""); + bizContent.put("terminalIp",payOrder.getClientIp()); + bizContent.put("frontUrl",getReturnUrl(payOrder.getPayOrderId())); + KqpayResp resp = KqpayKit.payRequest(KqpayConst.ReqMethod.A7009, mchAppConfigContext, bizContent,payOrder.getPayOrderId()); + this.initResult(resp,channelRetMsg); + ChannelJsapiMsg jsapiMsg = channelRetMsg.getJsapiMsg(); + if(jsapiMsg != null ){ + // 获取payInfo + String payInfo = JSON.toJSONString(jsapiMsg); + res.setPayInfo(payInfo); + res.setPayData(payInfo); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpClientCert.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpClientCert.java new file mode 100644 index 0000000..6a032cc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpClientCert.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.util; + +import lombok.Data; + +import java.security.KeyStore; + +@Data +public class HttpClientCert { + + /** + * 客户端证书 + */ + private KeyStore keyStore; + + /** + * 服务端证书 + */ + private KeyStore trustStore; + + /** + * 客户端证书密码 + */ + private String keyStorePwd; + + /** + * 服务端证书密码 + */ + private String trustStorePwd; + + /** + * 连接超时时间 + */ + private int soTimeout; + + /** + * 连接建立时间 + */ + private int connTimeout; + + /** + * SSL版本 + */ + private String SSLVersion; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpsClientFactory.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpsClientFactory.java new file mode 100644 index 0000000..db1e0df --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/HttpsClientFactory.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.util; + +import io.netty.util.internal.StringUtil; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.ssl.TrustStrategy; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.net.ssl.SSLContext; +import java.security.cert.X509Certificate; + +public class HttpsClientFactory { + + /* + * @method function 创建连接池 + */ + public CloseableHttpClient createSSLClient(HttpClientCert httpClientCert) throws Exception { + SSLContext sslContext = null; + SSLContextBuilder builder = SSLContexts.custom(); + // 加载客户端证书 + if(httpClientCert.getKeyStore() != null) { + if(ObjectUtils.isEmpty(httpClientCert.getKeyStorePwd())) { + builder = builder.loadKeyMaterial(httpClientCert.getKeyStore() , null); + }else { + builder = builder.loadKeyMaterial(httpClientCert.getKeyStore() , httpClientCert.getKeyStorePwd().toCharArray()); + } + } + // 加载服务端证书 + if(httpClientCert.getTrustStore() != null) { + sslContext = builder.loadTrustMaterial(httpClientCert.getTrustStore(), new TrustSelfSignedStrategy()).build(); + }else { + /** + * 客户端验证服务端 + */ + sslContext = builder.loadTrustMaterial(null, new TrustStrategy(){ + // 信任所有 + @Override + public boolean isTrusted(X509Certificate[] xcs, String string) { + return true; + } + }).build(); + } + SSLConnectionSocketFactory sslSocketFactory = getConnectionSocketFactory(sslContext,httpClientCert.getSSLVersion()); + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(httpClientCert.getSoTimeout()) + .setConnectTimeout(httpClientCert.getConnTimeout()).build(); + return HttpClients.custom().setDefaultRequestConfig(requestConfig).setSSLSocketFactory(sslSocketFactory).build(); + } + + private SSLConnectionSocketFactory getConnectionSocketFactory(SSLContext sslContext,String SSLVersion) { + if(ObjectUtils.isEmpty(SSLVersion)) { + return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + }else { + return new SSLConnectionSocketFactory(sslContext, new String[] { SSLVersion }, null, + NoopHostnameVerifier.INSTANCE); + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/KqpayConst.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/KqpayConst.java new file mode 100644 index 0000000..5bea398 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/kqpay/util/KqpayConst.java @@ -0,0 +1,78 @@ +package com.jeequan.jeepay.thirdparty.channel.kqpay.util; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class KqpayConst { + + public static final String DEV_APPLYMENTS_GATE_WAY = "https://sandbox.99bill.com:7445/umgw-boss/common/distribute.html"; + + public static final String APPLYMENTS_GATE_WAY = "https://umgw.99bill.com/umgw-boss/common/distribute.html"; + + /** + * 测试交易网关地址 + */ + public static final String DEV_TRADE_GATE_WAY = "https://sandbox.99bill.com:7445/umgw/common/distribute.html"; + + /** + * 正式交易网关地址 + */ + public static final String TRADE_GATE_WAY = "https://umgw.99bill.com/umgw/common/distribute.html"; + + public static final String SUCCESS = "0000"; + + public static final String BIZ_SUCCESS = "UMGW00086"; + + + + @AllArgsConstructor + @Getter + public enum ReqMethod { + BS000("BS000", "图片上传"), + BS001("BS001", "商户入网"), + BS002("BS002", "商户入网或变更状态查询"), + BS003("BS003", "签约状态查询"), + BS004("BS004", "发起签约"), + BS005("BS005", "商户变更"), + BS008("BS008", "开户意愿与个人授权"), + A5006("A5006", "异步通知"), + + A7001("A7001", "扫码支付"), + A7002("A7002", "扫码轮询"), + A7003("A7003", "扫码退货"), + A7004("A7004", "扫码撤销"), + A7005("A7005", "超时扫码撤销"), + A7006("A7006", "订单详情查询"), + A7007("A7007", "邀码"), + A7009("A7009", "统一下单"), + A9005("A9005", "收款结果异步通知"), + A9011("A9011", "异步分账修改"), + A9012("A9012", "异步分账确认"), + A9013("A9013a,A9013b", "分账查询"), + ; + + private final String messageType; + + private final String desc; + } + + @AllArgsConstructor + @Getter + public enum Package { + + MICRO("PSS-OFFLINE-001-001", "小微入网套餐"), + COMPANY("PSS-OFFLINE-001-003", "个体企业入网套餐"), + COMPANY_AUTO_ACTIVATION("PSS-OFFLINE-001-004", "门店收银畅享版"), + SETTLEMENT_EDIT("PSS-OFFLINE-004-001", "结算卡变更"), + COMPANY_BASE_EDIT("PSS-OFFLINE-003-002", "企业商户基本信息变更套餐"), + ACCOUNT_OPEN_LETTER("CRM-ONLINE-002-002", "平台合作商户结算及工商信息变更套餐"), + ; + + private final String code; + + private final String desc; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklpay/utils/LklpayConst.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklpay/utils/LklpayConst.java new file mode 100644 index 0000000..796fc91 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklpay/utils/LklpayConst.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.thirdparty.channel.lklpay.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LklpayConst { + + public static final Integer ACTIVITY_ID_WECHAT_PAY = 13; + + public static final Integer ACTIVITY_ID_B2B_SYT = 25; + + /** + * 专业扫码 + */ + public static final String BIZ_CODE_SCAN = "WECHAT_PAY"; + + /** + * B2B收银台 + */ + public static final String BIZ_CODE_B2B = "B2B_SYT"; + + public static final String POST = "POST"; + + public static final String GET = "GET"; + + public static final String CUSTOMER_NO = "{customerNo}"; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelNoticeService.java new file mode 100644 index 0000000..b074f9a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelNoticeService.java @@ -0,0 +1,94 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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 com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LKlsb2bCardType; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bTradeStatus; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 拉卡拉通知 回调接口实现类 + * + * @author crystal + */ +@Service +@Slf4j +public class Lklsb2bpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + JSONObject reqParamJSON = getReqParamJSON(); + String parOrderId = reqParamJSON.getString("out_order_no"); + return MutablePair.of(parOrderId, reqParamJSON); + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + JSONObject respJson = (JSONObject) JSONObject.toJSON(params); + log.info("拉卡拉【聚合收银台】回调参数:{}",respJson); + //验签成功后判断上游订单状态 + ResponseEntity okResponse = jsonResp(Lklsb2bpayKit.ok()); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); + Lklsb2bOrderStatus tradeStatus = Lklsb2bOrderStatus.getVal(respJson.getIntValue("order_status")); + JSONObject bizData = respJson.getJSONObject("order_trade_info"); + result.setPlatformMchOrderNo(bizData.getString("trade_no")); + result.setChannelOrderId(bizData.getString("log_no")); + result.setPlatformOrderNo(bizData.getString("acc_trade_no")); + result.setChannelUserId(bizData.getString("user_id2")); + String payMode = bizData.getString("pay_mode"); + result.setWayCodeType(payMode); + if("UQRCODEPAY".equals(payMode)){ + result.setWayCodeType(CS.PAY_WAY_CODE_TYPE.UNIONPAY); + } + LKlsb2bCardType acc_type = LKlsb2bCardType.getVal(bizData.getString("acc_type")); + result.setDrType(acc_type.getType()); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + switch (tradeStatus){ + case FAIL: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case EXPIRE: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case CANCEL: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + default: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + } + return result; + } + + + /** + * 验证银盛支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + return KqpayKit.checkResultNotify(jsonParams,mchAppConfigContext); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelUserService.java new file mode 100644 index 0000000..f698168 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayChannelUserService.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉 获取银联userId实现类 + * + * @author jmdhapy + * + * @date 2022/3/17 16:51 + */ +@Service +@Slf4j +public class Lklsb2bpayChannelUserService implements IChannelUserService { + + @Autowired + protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("redirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【拉卡拉获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + log.info("{} userAuthCode={}, appUpIdentifier={}", logPrefix, userAuthCode, appUpIdentifier); + JSONObject bizContent = new JSONObject(); + // 用户授权码 + bizContent.put("authCode", userAuthCode); + // 银联支付标识 + bizContent.put("appUpIdentifier", appUpIdentifier); + + MchApplyment mchApplyment = mchAppConfigContext.getMchApplyment(); + Lklsb2bpayIsvParams isvParams = (Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject respBizData = Lklsb2bpayKit.reqMch(Lklsb2bPayMethod.Api.USERID_QUERY, isvParams, bizContent); + return respBizData.getString("userId"); + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayDivisionService.java new file mode 100644 index 0000000..085c020 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayDivisionService.java @@ -0,0 +1,63 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分账接口 + * + * @author xiaoyu + * + * @date 2023/8/9 8:45 + */ +@Slf4j +@Service +public class Lklsb2bpayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..46fcec8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchAlipayConfigService.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class Lklsb2bpayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Lklsb2bpayIsvParams isvParams = (Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = Lklsb2bpayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("ZFBZF")) + .collect(Collectors.toList()); + + if (!filteredMercList.isEmpty()) { + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + result.setChannelSubMchId(subMchId); + } + + uWrapper.eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, "ZFB"); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getAliChannelExtUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (result.getChannelSubMchId() != null) { + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "ALIPAY") + .fluentPut("subMerchantId", result.getChannelSubMchId()); + + JSONObject respData = Lklsb2bpayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState) + || "UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + result.setState("未授权"); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState) + || "AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + result.setState("已授权"); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + + mchSubInfoService.update(null, uWrapper); + } + + + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..5f760a7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchApplymentNotifyService.java @@ -0,0 +1,269 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bb2bpay; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayMchApplymentService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; +import java.util.Optional; + +@Slf4j +@Service("lklsb2bpayIsvmchApplymentNotifyService") +public class Lklsb2bpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private Lklsb2bpayMchApplymentService lklsb2bpayMchApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public ResponseEntity retOk(Object params) { + return ResponseEntity.ok("success"); + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + + log.info("拉卡拉进件回调原始参数:{}", reqParamJSON); + RSA rsa = SecureUtil.rsa(null, Lklsb2bpayIsvParams.PUB_KEY); + String decryptData = rsa.decryptStr(reqParamJSON.getString("data"), KeyType.PublicKey); + log.info("拉卡拉进件回调解密参数: {}", decryptData); + + JSONObject bizJSON = JSON.parseObject(decryptData); + + String reviewRelatedId = bizJSON.getString(Lklsb2bpayConst.REVIEW_RELATED_ID); + String customerNo = bizJSON.getString(Lklsb2bpayConst.CUSTOMER_NO); + + if (!ObjectUtils.isEmpty(customerNo)) { + // 进件 + MchApplyment tbMchApplyment = mchApplymentService.getByOrderId(customerNo); + if (tbMchApplyment != null) { + return MutablePair.of(tbMchApplyment.getApplyId(), bizJSON); + } + } + + if (!ObjectUtils.isEmpty(reviewRelatedId)) { + // 变更 + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(reviewRelatedId, CS.IF_CODE.LKLSPAY); + if (mchModifyApplyment != null) { + return MutablePair.of(mchModifyApplyment.getApplyId(), bizJSON); + } + } + + return null; + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + JSONObject bizJSON = (JSONObject) params; + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String reviewRelatedId = bizJSON.getString(Lklsb2bpayConst.REVIEW_RELATED_ID); + String customerNo = bizJSON.getString(Lklsb2bpayConst.CUSTOMER_NO); + + if (!ObjectUtils.isEmpty(customerNo)) { + // 进件回调处理 + return doAuditNotify(bizJSON, mchApplyment, isvParams); + } + + if (!ObjectUtils.isEmpty(reviewRelatedId)) { + // 变更回调处理 + return doModifyNotify(reviewRelatedId, mchApplyment, bizJSON); + } + + return MutablePair.of(null, retOk(null)); + } + + public MutablePair doAuditNotify( + JSONObject bizJSON, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, Lklsb2bpayIsvParams isvParams) { + String status = bizJSON.getString("status"); + String remark = bizJSON.getString("remark"); + + mchApplyment.setRemark(remark); + + // 进件 + if ("SUCCESS".equals(status)) { + JSONObject param = new JSONObject(); + param.put("customerNo", mchApplyment.getChannelApplyNo()); + JSONObject respData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.AUDIT_STATUS_GET, isvParams, param); + + JSONObject customer = respData.getJSONObject("customer"); + JSONArray customerFeeList = respData.getJSONArray("customerFee"); + String termId = null; + // 将对应终端号下的终端id存下来 + for (int i = 0; i < customerFeeList.size(); i++) { + JSONObject customerFee = customerFeeList.getJSONObject(i); + String termNo = customerFee.getString("termNo"); + if (Objects.equals(termNo, customer.getString("termNo"))) { + termId = customerFee.getString("termId"); + break; + } + } + + String externalCustomerNo = customer.getString("externalCustomerNo"); + mchApplyment.setChannelMchNo(externalCustomerNo); + mchApplyment.setSuccResParameter(customer.toString()); + Optional.ofNullable(termId).ifPresent(t -> customer.put("termId", t)); + + lklsb2bpayMchApplymentService.subMchColl(mchApplyment); + // 进件通过 + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS); + + return MutablePair.of(mchApplyment, retOk(null)); + } else { + mchApplyment.setApplyErrorInfo(remark); + } + + String[] failStatusList = new String[]{ + "COMMIT_FAIL", + "FAILURE", + "INNER_CHECK_REJECTED" + }; + + if (ArrayUtil.contains(failStatusList, status)) { + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return MutablePair.of(mchApplyment, retOk(null)); + } + + public MutablePair doModifyNotify( + String reviewRelatedId, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, JSONObject bizJSON) { + // 变更 + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(reviewRelatedId, CS.IF_CODE.LKLSPAY); + + if (mchModifyApplyment == null) { + return MutablePair.of(mchApplyment, retOk(null)); + } + + if (!Objects.equals(mchModifyApplyment.getState(), MchApplyment.STATE_WAIT_SIGN) + && !Objects.equals(mchModifyApplyment.getState(), MchApplyment.STATE_AUDITING)) { + // 已经处理过,直接返回 + return MutablePair.of(null, retOk(null)); + } + + handleModifyApply(bizJSON, mchApplyment); + + return MutablePair.of(null, retOk(null)); + } + + private void handleModifyApply(JSONObject bizJSON, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String reviewPass = bizJSON.getString("reviewPass"); + String reviewRelatedId = bizJSON.getString("reviewRelatedId"); + String reviewResult = bizJSON.getString("reviewResult"); + + MchModifyApplyment modifyApplyment = getModifyApplymentByChannelApplyNo(reviewRelatedId); + + IIsvmchModifyApplymentService isvmchModifyApplymentService = IsvFactory.getIsvMchModifyApplymentService(CS.IF_CODE.LKLSPAY); + + if (mchApplyment.getState() == MchApplyment.STATE_SUCCESS) { + // 已经变更完成,直接退出 + return; + } + + + if (reviewPass.equals(Lklsb2bpayConst.EDIT_PASS)) { + // 变更成功 + handleSuccessfulChange(modifyApplyment, mchApplyment, isvmchModifyApplymentService); + } else { + // 其他状态统一定为驳回 + handleRejectedState(modifyApplyment, reviewResult); + } + } + + private MchModifyApplyment getModifyApplymentByChannelApplyNo(String channelApplyNo) { + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + qWrapper.eq(MchModifyApplymentEntity::getChannelApplyNo, channelApplyNo); + return mchInfoConverter.toModel(modifyApplymentService.getOne(qWrapper)); + } + + private void handleSuccessfulChange(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) { + MutablePair mchModifyPair; + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + mchModifyPair = isvmchModifyApplymentService.localModifyBase(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + mchModifyPair = isvmchModifyApplymentService.localModifySettlement(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_RATE: + mchModifyPair = isvmchModifyApplymentService.localModifyRate(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + mchModifyPair = isvmchModifyApplymentService.localModifySettlementType(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + default: + mchModifyPair = new MutablePair<>(modifyApplyment, mchApplyment); + } + + updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight()); + } + + private void handleRejectedState(MchModifyApplyment modifyApplyment, String note) { + MchModifyApplymentEntity result = new MchModifyApplymentEntity(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + result.setApplyErrorInfo("[" + note + "]"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + modifyApplymentService.updateById(result); + } + + private void updateModificationState(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + MchModifyApplymentEntity dbEntity = mchInfoConverter.toDbEntity(modifyApplyment); + MchApplyment dbEntity1 = mchInfoConverter.toDbEntity(mchApplyment); + + // 状态变更就更新 + if (!modifyApplyment.getState().equals(mchApplyment.getState())) { + modifyApplymentService.updateById(dbEntity); + + // 变更成功就更新商户数据 + if (modifyApplyment.getState() == MchApplyment.STATE_SUCCESS) { + mchApplymentService.updateById(dbEntity1); + } + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..279081a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchModifyApplymentService.java @@ -0,0 +1,366 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.Lklsb2bpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +public class Lklsb2bpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + Lklsb2bpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, Lklsb2bpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + Lklsb2bpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, Lklsb2bpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setIsLegalInfo("1".equals(mchModifyData.getIllegal()) ? "N" : "Y"); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setLetterOfAuthorizationImg(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair localModifySettlementType(MutablePair mchDataPair) { + String applyDetailInfo = mchDataPair.left.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + mchDataPair.left.setState(MchApplyment.STATE_SUCCESS_INEFFECTIVE); + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put(Lklsb2bpayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo()); + param.put("merBizName", mchModifyData.getMchShortName()); + // 其他属性暂不考虑 + + try { + JSONObject applyResp = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.BASE_INFO_CHANGE, isvParams, param); + Long reviewRelatedId = applyResp.getLong(Lklsb2bpayConst.REVIEW_RELATED_ID); + + resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId)); + resultModifyApplyment.setChannelVar1(applyResp.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String remark = "拉卡拉拓客基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("拉卡拉拓客基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put(Lklsb2bpayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo()); + param.put(Lklsb2bpayConst.ACCOUNT_NAME, mchModifyData.getSettAccountName()); + param.put(Lklsb2bpayConst.BANK_NAME, mchModifyData.getSettAccountBankName()); + param.put(Lklsb2bpayConst.BANK_NO, mchModifyData.getBankSubCode()); + param.put(Lklsb2bpayConst.CLEARING_BANK_NO, mchModifyData.getBankCode()); + param.put(Lklsb2bpayConst.ACCOUNT_NO, mchModifyData.getSettAccountNo()); + param.put("accountKind", mchModifyData.getSettAccountType().equals("B")? "57": "58"); + + List> attachments = new ArrayList<>(); + param.put("attachments", attachments); + if (mchModifyData.getSettAccountType().equals("B")) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "OPENING_PERMIT"); + Map attachmentItem = new HashMap<>(); + attachmentItem.put("imgPath", imgUploadResult.getString("url")); + attachmentItem.put("imgType", "OPENING_PERMIT"); + attachments.add(attachmentItem); + } + + if (mchModifyData.getSettAccountType().equals("C")) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "BANK_CARD"); + Map attachmentItem = new HashMap<>(); + attachmentItem.put("imgPath", imgUploadResult.getString("url")); + attachmentItem.put("imgType", "OPENING_PERMIT"); + attachments.add(attachmentItem); + } + + try { + JSONObject applyResp = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.SETTLE_CHANGE, isvParams, param); + Long reviewRelatedId = applyResp.getLong(Lklsb2bpayConst.REVIEW_RELATED_ID); + + resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId)); + resultModifyApplyment.setChannelVar1(applyResp.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String remark = "拉卡拉基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); +// log.debug("云商服3.0基本信息变更发起成功"); + log.debug("拉卡拉拓客基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + MchModifyApplymentModel modifyApplymentModel = JSON.parseObject(mchDataPair.left.getApplyDetailInfo(), MchModifyApplymentModel.class); + String settlementType = modifyApplymentModel.getSettlementType(); + + Lklsb2bpayApplymentInfo lklsb2bpayApplymentInfo = JSON.parseObject(mchDataPair.right.getApplyDetailInfo(), Lklsb2bpayApplymentInfo.class); + + JSONObject param = new JSONObject(); + param.put(Lklsb2bpayConst.CUSTOMER_NO, mchDataPair.right.getChannelApplyNo()); + + List fees = new ArrayList<>(); + Map feesMap = new HashMap(); + lklsb2bpayApplymentInfo.getPaywayFeeList().forEach(r -> { + + if (r.getWayCode().startsWith("WX_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "WECHAT"); + fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + } + + if (r.getWayCode().startsWith("ALI_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "ALIPAY"); + fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + } + + if (r.getWayCode().startsWith("YSF_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "YSF_DISCOUNT_DEBIT_FEE"); + fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "DEBIT_CARD"); + + // 费率模板限制 + fee.put("fee", "0.5d"); + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "YSF_DISCOUNT_CREDIT_FEE"); + fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100))); + + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "CREDIT_CARD"); + fee.put("fee", r.getLevelList().get(1).getFeeRate().multiply(BigDecimal.valueOf(100))); + + feesMap.put(fee.getString("feeType"), fee); + } + }); + + param.put("fees", new ArrayList<>(feesMap.values())); + param.put("settleType", settlementType); + param.put("productCode", Lklsb2bpayConst.BIZ_CODE_SCAN); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchDataPair.right)); + try { + JSONObject bizData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.RATE_CHANGE, isvParams, param); + + String message = bizData.getString("message"); + String reviewRelatedId = bizData.getString("reviewRelatedId"); + + if ("SUCCESS".equals(message)) { + mchDataPair.left.setChannelApplyNo(reviewRelatedId); + // 通过,次日生效,后续操作见定时任务 + mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData)); + mchDataPair.left.setState(MchApplyment.STATE_AUDITING); + + return new MutablePair<>(mchDataPair.left, null); + } else { + // 驳回 + mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData)); + mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchDataPair.left.setApplyErrorInfo("[" + message + "]"); + + return new MutablePair<>(mchDataPair.left, null); + } + } catch (Exception e) { + // 驳回 + mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchDataPair.left.setApplyErrorInfo("[" + e.getMessage() + "]"); + + return new MutablePair<>(mchDataPair.left, null); + } + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + MchApplyment mchApplyment = mchDataPair.getRight(); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + param.put(Lklsb2bpayConst.REVIEW_RELATED_ID, modifyApplyment.getChannelApplyNo()); + + JSONObject bizData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.CHANGE_STATUS_GET, isvParams, param); + String reviewPass = bizData.getString("reviewPass"); + String reviewResult = bizData.getString("reviewResult"); + if (!ObjectUtils.isEmpty(reviewResult)) { + resultModifyApplyment.setApplyErrorInfo("[" + reviewResult + "]"); + } + + if ("PASS".equals(reviewPass)) { + // 通过 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + return handleSuccessCase(modifyApplyment, mchDataPair); + } + + if ("UNPASS".equals(reviewPass)) { + // 驳回 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + bizData.getString("note") + "]"); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return mchDataPair; + } + + private MutablePair handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair mchDataPair) { + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + return localModifySettlementType(mchDataPair); + default: + return mchDataPair; + } + } + + private String processChannelValue(String channelVal, JSONObject bizData) { + JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal); + channelValJSON.putAll(bizData); + return channelValJSON.toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchWxConfigService.java new file mode 100644 index 0000000..d1e6e9d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayIsvmchWxConfigService.java @@ -0,0 +1,142 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class Lklsb2bpayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Lklsb2bpayIsvParams isvParams = (Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = Lklsb2bpayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("WXZF")) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(filteredMercList)) { + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + result.setChannelSubMchId(subMchId); + } + + uWrapper.eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, "WX"); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxOpenUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (result.getChannelSubMchId() != null) { + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "WECHAT") + .fluentPut("subMerchantId", result.getChannelSubMchId()); + + JSONObject respData = Lklsb2bpayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState) + || "UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + result.setState("未授权"); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + result.setState("已授权"); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + + mchSubInfoService.update(null, uWrapper); + } + + + return result; + } + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayKit.java new file mode 100644 index 0000000..1350bc5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayKit.java @@ -0,0 +1,625 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import cn.com.sand.hmpay.util.StringUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.PemUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.http.ContentType; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.*; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.HttpStatusCodeException; + +import javax.xml.bind.DatatypeConverter; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.PRECONDITION_FAILED; + +/** + * TODO + * + * @author crystal + * @date 2023/11/22 15:49 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Lklsb2bpayKit { + + public static final Logger log = LoggerFactory.getLogger(Lklsb2bpayKit.class); + + public static final String RESP_APPID_HEADER = "Lklapi-Appid"; + + public static final String RESP_SERIAL_HEADER = "Lklapi-Serial"; + + public static final String RESP_TIMESTAMP_HEADER = "Lklapi-Timestamp"; + + public static final String RESP_NONCE_HEADER = "Lklapi-Nonce"; + + public static final String RESP_SIGNATURE_HEADER = "Lklapi-Signature"; + + public static final String SCHEMA = "LKLAPI-SHA256withRSA"; + + public static final String SUCCESS_CODE = "000000"; + + public static final String EXT_SUCCESS_CODE = "BBS00000"; + + public static final String PAYING_SUCCESS_CODE = "BBS10000"; + + private static JSONObject token; + + private static JSONObject editToken; + + public static JSONObject uploadRequest(Lklsb2bpayIsvParams isvParams, String fileUrl, String imgType) { + reqAuditToken(isvParams); + + log.info("拉卡拉上传图片, 上传图片类型为{}, 上传图片链接为{}", imgType, fileUrl); + HttpRequest httpRequest = HttpRequest.post(LklTkReqMethod.UPLOAD.getUrl()) + .contentType(ContentType.MULTIPART.name()) + .header("Authorization", "bearer " + token.getString("access_token")); + + byte[] byteArray = HttpUtil.downloadBytes(fileUrl); + Image read = ImgUtil.toImage(byteArray); + + while (byteArray.length > 1024 * 1024) { + read = ImgUtil.scale(read, 0.9f); + byteArray = ImgUtil.toBytes(read, "jpg"); + } +// ByteArrayResource file = new ByteArrayResource(byteArray) { +// @Override +// public String getFilename() { +// return "test.jpg"; +// } +// }; + + httpRequest.form("file", byteArray, "test.jpg"); + httpRequest.form("imgType", imgType); + httpRequest.form("sourcechnl", "0"); + httpRequest.form("isOcr", false); + + HttpResponse execute = null; + try { + execute = httpRequest.execute(); + if (execute.isOk()) { + return JSON.parseObject(execute.body()); + } else { + log.info("拉卡拉上传图片异常, 上传图片类型为{}, 上传图片链接为{}", imgType, fileUrl); + throw new BizException("拉卡拉上传图片异常"); + } + + } catch (HttpStatusCodeException e) { + token = null; + throw e; + } finally { + if (execute != null) { + execute.close(); + } + } + } + + public static JSONObject uploadRequest(Lklsb2bpayIsvParams isvParams, File file, String imgType) { + reqAuditToken(isvParams); + + HttpRequest httpRequest = HttpRequest.post(LklTkReqMethod.UPLOAD.getUrl()) + .contentType(ContentType.MULTIPART.name()) + .header("Authorization", "bearer " + token.getString("access_token")); + + httpRequest.form("file", file); + httpRequest.form("imgType", imgType); + httpRequest.form("sourcechnl", "0"); + httpRequest.form("isOcr", false); + + HttpResponse execute = null; + try { + execute = httpRequest.execute(); + if (execute.isOk()) { + return JSON.parseObject(execute.body()); + } else { + log.info("拉卡拉上传图片异常, 上传图片类型为{}", imgType); + throw new BizException("拉卡拉上传图片异常"); + } + + } catch (HttpStatusCodeException e) { + token = null; + throw e; + } finally { + if (execute != null) { + execute.close(); + } + } + } + + private static void reqAuditToken(Lklsb2bpayIsvParams isvParams) { + token = getToken(isvParams); + } + + /** + * 获取入网token + * + * @return + */ + private static JSONObject getToken(Lklsb2bpayIsvParams isvParams) { + String clientInfo = isvParams.getClientId() + ":" + isvParams.getClientSecret(); + String encodeClientInfo = Base64.encode(clientInfo); + + try { + @Cleanup HttpResponse execute = HttpRequest.post(LklTkReqMethod.TOKEN_AUDIT.getUrl()) + .header("Authorization", "Basic " + encodeClientInfo) + .form("grant_type", "client_credentials") + .form("client_id", isvParams.getClientId()) + .form("client_secret", isvParams.getClientSecret()) + .execute(); + log.info("请求结果: {}", execute.body()); + JSONObject token = JSON.parseObject(execute.body()); + if (!execute.isOk()) { + throw new BizException(execute.body()); + } + token.put("expire_in", token.getIntValue("expire_in") + System.currentTimeMillis() / 1000L); + return token; + } catch (Exception e) { + log.info("token获取失败", e); + throw new BizException("token获取失败"); + } + } + + private static void reqAuditEditToken(Lklsb2bpayIsvParams isvParams) { + editToken = getEditToken(isvParams); + } + + private static JSONObject getEditToken(Lklsb2bpayIsvParams isvParams) { + String clientInfo = isvParams.getClientId() + ":" + isvParams.getClientSecret(); + String encodeClientInfo = Base64.encode(clientInfo); + + try { + @Cleanup HttpResponse execute = HttpRequest.post(LklTkReqMethod.TOKEN_EDIT.getUrl()) + .header("Authorization", "Basic " + encodeClientInfo) + .form("grant_type", "password") + .form("username", isvParams.getAppUserName()) + .form("password", isvParams.getAppPassword()) + .form("scope", "all") + .execute(); + log.info("请求结果: {}", execute.body()); + JSONObject token = JSON.parseObject(execute.body()); + if (!execute.isOk()) { + throw new BizException(execute.body()); + } + token.put("expire_in", token.getIntValue("expire_in") + System.currentTimeMillis() / 1000L); + return token; + } catch (Exception e) { + log.info("token获取失败", e); + throw new BizException("token获取失败"); + } + } + + public static JSONObject applymentRequest(ILklTkReqMethod reqMethod, Lklsb2bpayIsvParams isvParams, JSONObject param) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉配置信息"); + + if (reqMethod.getUrlFlag().equals(Lklsb2bpayConst.AUDIT)) { + reqAuditToken(isvParams); + } else { + reqAuditEditToken(isvParams); + } + + String url = reqMethod.getUrl(); + String templateWord = reqMethod.getTemplateWord(); + if (!ObjectUtils.isEmpty(templateWord)) { + String paramWord = param.getString(templateWord.replaceAll("[{}]", "")); + url = url.replace(templateWord, paramWord); + } + + log.info("拉卡拉请求链接: {}", url); + log.info("拉卡拉请求参数: {}", param); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(reqMethod.getContentType()); + if (reqMethod.getUrlFlag().equals(Lklsb2bpayConst.AUDIT)) { + headers.add("Authorization", "bearer " + token.getString("access_token")); + } else { + headers.add("Authorization", "bearer " + editToken.getString("access_token")); + } + log.info("拉卡拉请求头:{}", JSON.toJSONString(headers)); + + if (reqMethod.getContentType().equals(MediaType.APPLICATION_FORM_URLENCODED)) { + + HttpResponse execute = null; + if (reqMethod.getMethod().equals(LklpayConst.POST)) { + try { + HttpRequest httpRequest = HttpRequest.post(url); + if (reqMethod.getUrlFlag().equals(Lklsb2bpayConst.AUDIT)) { + httpRequest.header("Authorization", "bearer " + token.getString("access_token")); + } else { + httpRequest.header("Authorization", "bearer " + editToken.getString("access_token")); + } + + for (Map.Entry entry : param.entrySet()) { + httpRequest.form(entry.getKey(), entry.getValue()); + } + + execute = httpRequest.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + throw new BizException(body); + } + + } catch (HttpStatusCodeException e) { + token = null; + handleHttpStatusCodeException(e); + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + throw new BizException("拉卡拉请求异常"); + } finally { + if (execute != null) { + execute.close(); + } + } + } + + if (reqMethod.getMethod().equals(Lklsb2bpayConst.GET)) { + try { + url += "?"; + + HttpRequest httpRequest = HttpRequest.get(url); + + if (reqMethod.getUrlFlag().equals(Lklsb2bpayConst.AUDIT)) { + httpRequest.header("Authorization", "bearer " + token.getString("access_token")); + } else { + httpRequest.header("Authorization", "bearer " + editToken.getString("access_token")); + } + + for (Map.Entry entry : param.entrySet()) { + httpRequest.form(entry.getKey(), entry.getValue()); + } + execute = httpRequest.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + throw new BizException(body); + } + } catch (HttpStatusCodeException e) { + token = null; + handleHttpStatusCodeException(e); + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + throw new BizException("拉卡拉请求异常"); + } finally { + if (execute != null) { + execute.close(); + } + } + } + } + + if (MediaType.APPLICATION_JSON.equals(reqMethod.getContentType())) { + RSA rsa = null; + HttpRequest post = HttpRequest.post(url).header(headers); + if (reqMethod.isEncrypt()) { + rsa = SecureUtil.rsa(LklTkReqMethod.PRI_KEY, LklTkReqMethod.PUB_KEY); + String encryptBase64 = rsa.encryptBase64(param.toJSONString(), KeyType.PrivateKey); + JSONObject reqParam = new JSONObject(); + reqParam.put("data", encryptBase64); + post.body(reqParam.toJSONString()); + } else { + post.body(param.toJSONString()); + } + + try { + @Cleanup HttpResponse execute = post.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + + JSONObject respData = JSON.parseObject(body); + String encryptData = respData.getString("data"); + if (reqMethod.isEncrypt()) { + String encryptRespData = rsa.decryptStr(encryptData, KeyType.PublicKey); + log.info("拉卡拉请求返回结果解密:{}", encryptRespData); + + return JSON.parseObject(encryptRespData); + } + + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + + if (execute.getStatus() == 400 || execute.getStatus() == 412 || execute.getStatus() == 500) { + throw new BizException(JSON.parseObject(body).getString("message")); + } + + throw new BizException(body); + } + + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + if (e instanceof BizException) { + throw e; + } + throw new BizException("拉卡拉请求异常, " + e.getMessage()); + } + } + + throw new BizException("拉卡拉请求异常"); + } + + public static JSONObject openRequest(ILklTkReqMethod method, Lklsb2bpayIsvParams isvParams, JSONObject params) { + JSONObject reqParam = new JSONObject(); + reqParam.put("ver", "v1.0.0"); + reqParam.put("timestamp", String.valueOf(System.currentTimeMillis())); + reqParam.put("rnd", UUID.randomUUID().toString().replace("-", "")); + reqParam.put("reqId", UUID.randomUUID().toString().replace("-", "")); + reqParam.put("reqData", params); + + Map headers = getAuthorization(isvParams, reqParam.toString()); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqParam.toString()).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + checkSign(isvParams, response); + return JSON.parseObject(response.body()).getJSONObject("respData"); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + return new JSONObject(); + } + } + + public static Map getAuthorization(Lklsb2bpayIsvParams isvParams, String body) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉入网配置信息"); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPrivateCert()); + InputStream inputStream = FileUtil.getInputStream(certFilePath); + String nonceStr = RandomUtil.randomString(16); + Map headers = new HashMap<>(1); + long timestamp = System.currentTimeMillis() / 1000; + String data = isvParams.getAppId() + "\n" + isvParams.getSerialNo() + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"; + byte[] privateKey = PemUtil.readPem(inputStream); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKey, null); + sign.sign(data); + String signature = Base64.encode(sign.sign(data)); + try { + String authorization = "appid=\"" + isvParams.getAppId() + "\"," + "serial_no=\"" + isvParams.getSerialNo() + "\"," + "timestamp=\"" + + timestamp + "\"," + "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\""; + headers.put("Authorization", SCHEMA + " " + authorization); + log.info("【拉卡拉】接口请求参数:{}",body); + return headers; + } catch (Exception e) { + throw new BizException("拉卡拉接口授权参数异常"); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static boolean checkSign(Lklsb2bpayIsvParams isvParams, HttpResponse response) { + String respAppid = response.header(RESP_APPID_HEADER); + String respSerial = response.header(RESP_SERIAL_HEADER); + String respTimestamp = response.header(RESP_TIMESTAMP_HEADER); + String respNonce = response.header(RESP_NONCE_HEADER); + String repsSignature = response.header(RESP_SIGNATURE_HEADER); + String source = respAppid + "\n" + respSerial + "\n" + respTimestamp + "\n" + respNonce + "\n" + response.body() + "\n"; + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉入网配置信息"); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicCert()); + InputStream inputStream = FileUtil.getInputStream(certFilePath); + try { + Certificate certificate = SecureUtil.readX509Certificate(inputStream); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA).setCertificate(certificate); + return sign.verify(source.getBytes(StandardCharsets.UTF_8), DatatypeConverter.parseBase64Binary(repsSignature)); + } catch (Exception e) { + return false; + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 设置通道参数 + * + * @param mchAppConfigContext + * @param bizContent + */ + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String ip) { + Lklsb2bpayIsvsubMchParams mchParams = JSON.parseObject(mchAppConfigContext.getMchApplyment().getSuccResParameter(), Lklsb2bpayIsvsubMchParams.class); + bizContent.put("merchant_no", mchParams.getExternalCustomerNo()); + bizContent.put("term_no", mchParams.getTermNo()); + if (StringUtil.isNotEmpty(ip)) { + JSONObject location_info = new JSONObject(1); + location_info.put("request_ip", ip); + bizContent.put("location_info", location_info); + } + } + + /** + * 请求 + * + * @return + */ + public static JSONObject payRequest(Lklsb2bPayMethod.Api method, MchApplyment mchApplyment, JSONObject params) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + JSONObject reqParam = new JSONObject(); + reqParam.put("version", "3.0"); + reqParam.put("req_time", DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_FORMAT)); + reqParam.put("req_data", params); + Map headers = getAuthorization(isvParams, reqParam.toString()); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqParam.toString()).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + JSONObject responseBody = JSON.parseObject(response.body()); + if(!EXT_SUCCESS_CODE.equals(responseBody.getString("code")) && !PAYING_SUCCESS_CODE.equals(responseBody.getString("code")) && !SUCCESS_CODE.equals(responseBody.getString("code"))){ + throw new BizException(responseBody.getString("msg")); + } + checkSign(isvParams, response); + return responseBody.getJSONObject("resp_data"); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + return new JSONObject(); + } + } + + public static void handleHttpClientErrorException(HttpStatusCodeException e) { + log.info("http code exception", e); + byte[] responseBodyAsByteArray = e.getResponseBodyAsByteArray(); + String resp = new String(responseBodyAsByteArray, StandardCharsets.UTF_8); + log.info("拉卡拉请求返回结果:{}", resp); + JSONObject error = JSON.parseObject(resp); + String errorMsg; + String msg; + HttpStatus statusCode = e.getStatusCode(); + if (statusCode.equals(BAD_REQUEST) || statusCode.equals(PRECONDITION_FAILED)) { + errorMsg = error.getString("message"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(msg); + } else { + errorMsg = StringUtil.isNotEmpty(error.getString("retMsg")) ? error.getString("retMsg") : error.getString("msg"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(msg); + } + } + + public static void handleHttpStatusCodeException(HttpStatusCodeException e) { + log.info("拉卡拉请求异常返回码", e); + byte[] responseBodyAsByteArray = e.getResponseBodyAsByteArray(); + String resp = new String(responseBodyAsByteArray, StandardCharsets.UTF_8); + log.info("拉卡拉请求返回结果:{}", resp); + + JSONObject error = JSON.parseObject(resp); + String errorMsg; + String msg; + switch (e.getStatusCode()) { + case BAD_REQUEST: + case PRECONDITION_FAILED: + // 汇拓客的接口 + errorMsg = error.getString("message"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(errorMsg); + default: + errorMsg = StringUtil.isNotEmpty(error.getString("retMsg")) ? error.getString("retMsg") : error.getString("msg"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + break; + } + + throw e; + } + + public static JSONObject ok() { + JSONObject result = new JSONObject(2); + result.put("code", "SUCCESS"); + result.put("message", "处理成功"); + return result; + } + + /** + * 商户相关参数请求 + * + * @param method + * @param bizContent + * @return + */ + public static JSONObject reqMch(Lklsb2bPayMethod.Api method, Lklsb2bpayIsvParams isvParams, JSONObject bizContent) { + if (method == Lklsb2bPayMethod.Api.WECHAT_PARAMS_CONFIG_URL) { + bizContent.put("channlId", isvParams.getWxChannelId()); + } + Lklb2bMchReq req = new Lklb2bMchReq(bizContent); + return reqApi(method, isvParams, JSON.toJSONString(req)); + } + + public static JSONObject reqApi(Lklsb2bPayMethod.Api method, Lklsb2bpayIsvParams isvParams, String reqBody) { + log.info("【拉卡拉】接口请求地址:{}",method.getUrl()); + Map headers = getAuthorization(isvParams, reqBody); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqBody).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + return initResult(isvParams, response); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + throw new BizException("接口异常"); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 发起结算信息请求 + * + * @param method + * @param bizData + * @param isvParams + * @return + */ + public static JSONObject reqSettle(Lklsb2bPayMethod.Api method, JSONObject bizData, Lklsb2bpayIsvParams isvParams) { + Lklsb2bSettleReq reqData = new Lklsb2bSettleReq(bizData); + return reqApi(method, isvParams, JSON.toJSONString(reqData)); + } + + private static JSONObject initResult(Lklsb2bpayIsvParams isvParams, HttpResponse response) { + boolean verify = checkSign(isvParams, response); + if (!verify) { + throw new BizException("签名校验异常"); + } + JSONObject responseBody = JSON.parseObject(response.body()); + String retCode = responseBody.getString("retCode"); + if (!SUCCESS_CODE.equals(retCode)) { + throw new BizException(responseBody.getString("retMsg")); + } + Object respData = responseBody.get("respData"); + if(respData instanceof JSONObject){ + return (JSONObject) respData; + } + return responseBody; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApiService.java new file mode 100644 index 0000000..38430d9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApiService.java @@ -0,0 +1,572 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bb2bpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.applyment.Lklsb2bpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +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 com.jeequan.jeepay.db.entity.BankBranchLkl; +import com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.service.mapper.BankBranchLklMapper; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bMercInfoConn; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; + +/** + * TODO + * + * @author crystal + * @since 2023/12/4 10:47 + */ +@Service +@Slf4j +public class Lklsb2bpayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private Configuration configuration; + + @Autowired + private BankBranchLklMapper bankBranchLklMapper; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + private String getEndDate(String endDate) { + if ("长期".equals(endDate)) { + return "2099-12-31"; + } + + return endDate; + } + + private Lklsb2bMercInfoConn getLklData(Lklsb2bpayApplymentInfo applymentInfo, Lklsb2bpayIsvParams isvParams) { + Lklsb2bMercInfoConn mercInfo = new Lklsb2bMercInfoConn(); + mercInfo.setUserNo(Long.parseLong(isvParams.getUserNo())); + mercInfo.setEmail("18062761507@163.com"); + mercInfo.setBusiCode(LklpayConst.BIZ_CODE_B2B); + + if (MchApplyment.MERCHANT_TYPE_PERSONAL == applymentInfo.getMerchantType()) { + mercInfo.setMerType("TP_PERSONAL"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } else { + mercInfo.setMerType("TP_MERCHANT"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } + + mercInfo.setMerName(applymentInfo.getMchShortName()); + mercInfo.setMerAddr(applymentInfo.getAddress()); + + mercInfo.setProvinceCode(applymentInfo.getMchAreaCode().getString(0)); + mercInfo.setCityCode(applymentInfo.getMchAreaCode().getString(1)); + mercInfo.setCountyCode(applymentInfo.getMchAreaCode().getString(2)); + + if (1 != applymentInfo.getMerchantType()) { + // 非小微商户提交营业执照信息 + mercInfo.setLicenseName(applymentInfo.getMchFullName()); + mercInfo.setLicenseNo(applymentInfo.getLicenseNo()); + mercInfo.setLicenseDtStart(applymentInfo.getLicenseEffectBegin()); + mercInfo.setLicenseDtEnd(getEndDate(applymentInfo.getLicenseEffectEnd())); + } + // 接口的经纬度字段是反的 + mercInfo.setLatitude(applymentInfo.getLatitude()); + mercInfo.setLongtude(applymentInfo.getLongtude()); + mercInfo.setSource("APP"); + + Assert.notNull(applymentInfo.getMccCode(), "缺少mcc编码信息"); + String[] mccInfo = applymentInfo.getMccCode().split("_"); + if (mccInfo.length != 2) { + throw new BizException("mcc数据异常"); + } + mercInfo.setBusinessContent(mccInfo[0]); + mercInfo.setLarName(applymentInfo.getIdcardName()); + mercInfo.setLarIdType("01"); + mercInfo.setLarIdCard(applymentInfo.getIdcardNo()); + mercInfo.setLarIdCardStart(applymentInfo.getIdcardEffectBegin()); + mercInfo.setLarIdCardEnd(getEndDate(applymentInfo.getIdcardEffectEnd())); + mercInfo.setContactMobile(applymentInfo.getContactPhone()); + mercInfo.setContactName(applymentInfo.getContactName()); + + BankBranchLkl bankCodeLkl = bankBranchLklMapper.selectByContactLine(applymentInfo.getOpenningBankCode()); + Assert.notNull(bankCodeLkl, "未获取到支行信息,请重新选择支行信息"); + + mercInfo.setOpenningBankCode(bankCodeLkl.getContactLine()); + mercInfo.setOpenningBankName(bankCodeLkl.getBranchName()); + mercInfo.setClearingBankCode(bankCodeLkl.getClearNo()); + + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaCode(), "缺少支行地区编码信息"); + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaName(), "缺少支行地区信息"); + mercInfo.setSettleProvinceCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(0)); + mercInfo.setSettleProvinceName(applymentInfo.getSettAccountBankBranchAreaName().getString(0)); + mercInfo.setSettleCityCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(1)); + mercInfo.setSettleCityName(applymentInfo.getSettAccountBankBranchAreaName().getString(1)); + mercInfo.setAccountNo(applymentInfo.getSettAccountNo()); + mercInfo.setAccountName(applymentInfo.getSettAccountName()); + mercInfo.setAccountType(applymentInfo.getSettAccType()); + mercInfo.setAccountIdType("01"); + mercInfo.setAccountIdCard(applymentInfo.getSettAccountIdcardNo()); + mercInfo.setAccountIdDtStart(applymentInfo.getSettAccountIdcardEffectBegin()); + mercInfo.setAccountIdDtEnd(getEndDate(applymentInfo.getSettAccountIdcardEffectEnd())); + + mercInfo.setBizContent(getFeeInfo(applymentInfo, isvParams)); + mercInfo.setSettleType(applymentInfo.getSettleType()); + mercInfo.setSettlementType("AUTOMATIC"); + + return mercInfo; + } + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + private Lklsb2bMercInfoConn.BizContent getFeeInfo(Lklsb2bpayApplymentInfo applymentInfo, Lklsb2bpayIsvParams isvParams) { + Map map = new HashMap<>(); + + List paywayFeeList = applymentInfo.getPaywayFeeList(); + + for (PaywayFee paywayFee : paywayFeeList) { + boolean isYsfLevelFee = (paywayFee.getWayCode().startsWith("YSF_") || paywayFee.getWayCode().startsWith("UP_")) + && PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) + && CollUtil.isNotEmpty(paywayFee.getLevelList()); + if (isYsfLevelFee) { + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + map.put("YSF_DISCOUNT_DEBIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee1)); + + PaywayFee paywayFee2DebitCard = paywayFee.getLevelList().get(1); + double topFee2 = (double) paywayFee2DebitCard.getMaxFee() / 100L; + map.put("DEBIT_CARD", new Lklsb2bMercInfoConn.Fee("DEBIT_CARD", 0.5d, topFee2)); +// map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee2)); + } + + PaywayFee creditCardPaywayFee = paywayFee.getCreditCardPaywayFee(); + if (creditCardPaywayFee != null && CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()) && (CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()))) { + PaywayFee paywayFeeCrebitCard = creditCardPaywayFee.getLevelList().get(0); + map.put("YSF_DISCOUNT_CREDIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFeeCrebitCard.getFeeRate())), null)); + + PaywayFee paywayFee2CrebitCard = creditCardPaywayFee.getLevelList().get(1); + map.put("CREDIT_CARD", new Lklsb2bMercInfoConn.Fee("CREDIT_CARD", Double.parseDouble(convertRate(paywayFee2CrebitCard.getFeeRate())), null)); + + } + + if (paywayFee.getWayCode().startsWith("WX_")) { + map.put("WECHAT", new Lklsb2bMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + + if (paywayFee.getWayCode().startsWith("ALI_")) { + map.put("ALIPAY", new Lklsb2bMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + if (CS.PAY_WAY_CODE.D0.equals(paywayFee.getWayCode())) { + // D0费率 + double d0Rate = Double.parseDouble(convertRate(paywayFee.getFeeRate())); + // 扫码d0费率 + map.put("SCAN_PAY_SECOND", new Lklsb2bMercInfoConn.Fee("SCAN_PAY_SECOND", d0Rate, null)); + // 刷卡D0费率 + map.put("CARD_SECOND", new Lklsb2bMercInfoConn.Fee("CARD_SECOND", d0Rate, null)); + } + + if (CS.PAY_WAY_CODE.SCAN.equals(paywayFee.getWayCode())) { + // 线上费率 + map.put("WECHAT", new Lklsb2bMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + map.put("ALIPAY", new Lklsb2bMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + // 银联借记卡,云闪付优惠费率,1000以下的交易费率 + map.put("YSF_DISCOUNT_DEBIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFee.getFeeRate())), topFee1)); + + // 银联费率有银联费率模版限制,写死,一般不用作实际交易 + map.put("DEBIT_CARD", new Lklsb2bMercInfoConn.Fee("DEBIT_CARD", 0.5d, 20d)); + // 银联贷记卡,云闪付优惠费率,1000以下的交易费率 + map.put("YSF_DISCOUNT_CREDIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + map.put("CREDIT_CARD", new Lklsb2bMercInfoConn.Fee("CREDIT_CARD", 0.6d, null)); + } + } + + Lklsb2bMercInfoConn.BizContent bizContent = new Lklsb2bMercInfoConn.BizContent(); + + String[] mccInfo = applymentInfo.getMccCode().split("_"); + bizContent.setMcc(mccInfo[1]); + // 25为B2B收银台 13位专业扫码 + bizContent.setActivityId(LklpayConst.ACTIVITY_ID_B2B_SYT); + bizContent.setTermNum("1"); + bizContent.setFees(new HashSet<>(map.values())); + + return bizContent; + } + + private File writeHtml(Template template, Lklsb2bpayApplymentInfo lklsb2bpayApplymentInfo, Lklsb2bpayIsvParams isvParams) throws IOException, TemplateException { + Map param = new HashMap<>(); + Map fee = new HashMap<>(); + + Lklsb2bMercInfoConn lklData = getLklData(lklsb2bpayApplymentInfo, isvParams); + fee.put("customerName", Optional.ofNullable(lklData.getContactName()).orElse("")); + param.put("fee", fee); + param.put("licenseNo", Optional.ofNullable(lklData.getLicenseNo()).orElse("")); + param.put("legalName", Optional.ofNullable(lklData.getLarName()).orElse("")); + param.put("licenseName", Optional.ofNullable(lklData.getLicenseName()).orElse("")); + param.put("identityNo", Optional.ofNullable(lklData.getLarIdCard()).orElse("")); + param.put("address", lklData.getMerAddr()); + param.put("receiveDetail", Optional.ofNullable(lklData.getMerAddr()).orElse("")); + param.put("identityNoExpire", Optional.ofNullable(getEndDate(lklData.getLicenseDtEnd())).orElse("")); + param.put("accountName", Optional.ofNullable(lklData.getAccountName()).orElse("")); + param.put("accountIdCard", Optional.ofNullable(lklData.getAccountIdCard()).orElse("")); + param.put("accountNo", Optional.ofNullable(lklData.getAccountNo()).orElse("")); + param.put("accountIdDtEnd", Optional.ofNullable(getEndDate(lklData.getAccountIdDtEnd())).orElse("")); + param.put("bankName", Optional.ofNullable(lklData.getOpenningBankName()).orElse("")); + param.put("mail", Optional.ofNullable(lklData.getEmail()).orElse("")); + param.put("contactManName", Optional.ofNullable(lklData.getContactName()).orElse("")); + param.put("channelType", Optional.ofNullable(lklData.getMerType()).orElse("")); + param.put("phone", Optional.ofNullable(lklData.getContactMobile()).orElse("")); + param.put("agencyName", "拉卡拉"); + param.put("width", "600px"); + param.put("tbTitleWidth", "60px"); + param.put("tbConWidth", "60px"); + + String fileName = UUID.randomUUID().toString(); + File htmlFile = new File(FileUtil.getTmpDir(), fileName + ".html"); + FileWriter sw = new FileWriter(htmlFile); + log.info("生成协议html, 地址:{}, 参数:{} ", htmlFile.getAbsolutePath(), param); + template.process(param, sw); + + return htmlFile; + } + + private static File createAgreementPicture(File htmlFile) throws IOException { + File outputFile = new File(FileUtil.getTmpDir(), htmlFile.getName() + ".jpg"); + log.info("生成图片开始, HTML地址 {}, 图片地址:{}", htmlFile.getAbsolutePath(), outputFile.getAbsolutePath()); + /** + * 生成图片说明,需要在服务器上安装需要的字体,等线字体即可,可在windows系统字体库中获得 + * 将字体放在服务器/usr/share/fonts/myfonts目录中, + * 运行 sudo fc-cache -f -v 命令 即可刷新字体缓存 + */ + String commandProcess = "wkhtmltoimage --width 400 --quality 94 " + htmlFile.getPath() + " " + outputFile.getPath(); + log.info("协议执行Process command:{}", commandProcess); + long startTime = System.currentTimeMillis(); //获取开始时间 + Process process = Runtime.getRuntime().exec(commandProcess); + try { + int exitVal = process.waitFor(); + log.info("协议html转换png结果:{}", exitVal); + } catch (InterruptedException e) { + log.info("协议html转换png错误", e); + Thread.currentThread().interrupt(); + throw new IOException(e); + } + long endTime = System.currentTimeMillis(); //获取结束时间 + log.info("程序运行时间: " + (endTime - startTime) + "ms"); + log.info("生成图片结束,地址: {}", outputFile.getPath()); + Thumbnails.of(outputFile).scale(1).outputQuality(0.9).toFile(outputFile); + return outputFile; + } + + public MchApplyment submitMchInfo(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + + String channelVar1 = mchApplyment.getChannelVar1(); + Type type = new TypeReference>() { + }.getType(); + Set attachments = JSON.parseObject(channelVar1, type); + + Lklsb2bpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), Lklsb2bpayApplymentInfo.class); + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode())); + + Lklsb2bMercInfoConn lklData = getLklData(applymentInfo, isvParams); + + lklData.setAttchments(attachments); + + JSONObject resp = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.AUDIT, isvParams, (JSONObject) JSON.toJSON(lklData)); + String status = resp.getString("status"); + String customerNo = resp.getString("merchantNo"); + if (status.equals("WAIT_AUDI")) { + result.setState(MchApplyment.STATE_AUDITING); + result.setChannelApplyNo(customerNo); + } + + // 进件响应参数 + result.setSettlementType(applymentInfo.getSettleType()); + result.setState(MchApplyment.STATE_AUDITING); + + return result; + } + + public MchApplyment uploadImg(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + + File agreementPicture; + + Lklsb2bpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), Lklsb2bpayApplymentInfo.class); + Assert.notNull(applymentInfo.getAreaName(), "经营地区名称[areaName]不能为空"); + Assert.isFalse(applymentInfo.getAreaName().isEmpty(), "经营地区名称[areaName]不能为空"); + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode())); + + try { + Template template = configuration.getTemplate("lkltkpay/indexHTKWECHAT_PAY.html.ftl"); + File file = writeHtml(template, applymentInfo, isvParams); + agreementPicture = createAgreementPicture(file); + } catch (Exception e) { + log.info("创建拉卡拉汇拓客协议图片失败", e); + throw new BizException("创建拉卡拉汇拓客协议图片失败, " + e.getMessage()); + } + + Set attachments = new HashSet<>(); + uploadRequest(attachments, "AGREE_MENT", agreementPicture, isvParams); + uploadRequest(attachments, "SHOP_OUTSIDE_IMG", applymentInfo.getStoreOuterImg(), isvParams); + uploadRequest(attachments, "SHOP_INSIDE_IMG", applymentInfo.getStoreInnerImg(), isvParams); + uploadRequest(attachments, "CHECKSTAND_IMG", applymentInfo.getStoreCashierImg(), isvParams); + uploadRequest(attachments, "ID_CARD_FRONT", applymentInfo.getIdcard1Img(), isvParams); + uploadRequest(attachments, "ID_CARD_BEHIND", applymentInfo.getIdcard2Img(), isvParams); + + if (applymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + uploadRequest(attachments, "BUSINESS_LICENCE", applymentInfo.getLicenseImg(), isvParams); + + if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(applymentInfo.getSettAccountType())) { + uploadRequest(attachments, "BANK_CARD", applymentInfo.getSettAccountLicenseImg(), isvParams); + } + + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(applymentInfo.getSettAccountType())) { + uploadRequest(attachments, "OPENING_PERMIT", applymentInfo.getCompanyAccountLicenseImg(), isvParams); + } + } + + if (!"1".equals(applymentInfo.getIsLegalInfo())) { + uploadRequest(attachments, "SETTLE_ID_CARD_FRONT", applymentInfo.getSettAccountIdcard1Img(), isvParams); + uploadRequest(attachments, "SETTLE_ID_CARD_BEHIND", applymentInfo.getSettAccountIdcard2Img(), isvParams); + uploadRequest(attachments, "LETTER_OF_AUTHORIZATION", applymentInfo.getLetterOfAuthorizationImg(), isvParams); + } else { + uploadRequest(attachments, "SETTLE_ID_CARD_FRONT", applymentInfo.getIdcard1Img(), isvParams); + uploadRequest(attachments, "SETTLE_ID_CARD_BEHIND", applymentInfo.getIdcard2Img(), isvParams); + } + + result.setState(MchApplyment.STATE_AUDITING_WAIT); + result.setRemainStep((byte) 1); + + result.setChannelVar1(JSON.toJSONString(attachments)); + + return result; + } + + public void uploadRequest(Set attachmentList, String key, File file, Lklsb2bpayIsvParams isvParams) { + attachmentList.add(getAttachment(isvParams, file, key)); + } + + public void uploadRequest(Set attachmentList, String key, String imgUrl, Lklsb2bpayIsvParams isvParams) { + // 下载文件 + Lklsb2bMercInfoConn.Attachment attach = getAttachment(isvParams, imgUrl, key); + attachmentList.add(attach); + } + + private static Lklsb2bMercInfoConn.Attachment getAttachment(Lklsb2bpayIsvParams isvParams, File file, String imgType) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, file, imgType); + Lklsb2bMercInfoConn.Attachment attachmentItem = new Lklsb2bMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private static Lklsb2bMercInfoConn.Attachment getAttachment(Lklsb2bpayIsvParams isvParams, String fileUrl, String imgType) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, fileUrl, imgType); + Lklsb2bMercInfoConn.Attachment attachmentItem = new Lklsb2bMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * mchRq + * + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + preWxParamsCheck(mchRq); + JSONObject bizData = new JSONObject(); + bizData.put("merCupNo", applyment.getChannelMchNo()); + if (ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())) { + bizData.put("confType", "JSAPI_PATH"); + bizData.put("jsapiPath", mchRq.getJsapiPath()); + } else { + bizData.put("subAppid", mchRq.getAppid()); + bizData.put("confType", "SUB_APPID"); + } + bizData.put("subMchId", mchRq.getSubMchNo()); + Lklsb2bpayIsvParams isvParams = (Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(applyment); + JSONObject result = Lklsb2bpayKit.reqMch(Lklsb2bPayMethod.Api.WECHAT_PARAMS_CONFIG_URL, isvParams, bizData); + return ChannelRetMsg.confirmSuccess(null); + } + + /** + * 校验拉卡拉微信参数配置 + * + * @param mchRq + */ + private void preWxParamsCheck(ChannelMchRq mchRq) { + if (StringUtils.isEmpty(mchRq.getSubMchNo())) { + throw new BizException("调用拉卡拉配置微信参数接口失败,缺失微信子商户号[subMchNo]参数"); + } + } + + /** + * 拉卡拉查询结算信息接口 + * + * @param settleRq + * @param isvParams + * @return + */ + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, Lklsb2bpayIsvParams isvParams) { + super.preSettleCheck(settleRq); + if (StringUtils.isBlank(settleRq.getMercNo())) { + throw new BizException("缺失商户号"); + } + JSONObject bizData = new JSONObject(); + bizData.put("merchantNo", settleRq.getMercNo()); + bizData.put("startDate", DateUtil.format(settleRq.getStartDate(), DatePattern.PURE_DATE_PATTERN)); + bizData.put("endDate", DateUtil.format(settleRq.getEndDate(), DatePattern.PURE_DATE_PATTERN)); + bizData.put("page", settleRq.getPage()); + bizData.put("size", settleRq.getSize()); + JSONObject respData = Lklsb2bpayKit.reqSettle(Lklsb2bPayMethod.Api.SETTLE_QUERY, bizData, isvParams); + JSONArray resultList = respData.getJSONArray("respData"); + if(resultList.isEmpty()){ + return null; + } + //拉卡拉只支持单商户结算记录查询 + List result = new ArrayList<>(1); + for (Object item:resultList) { + JSONObject respBizData = (JSONObject)item; + JSONObject stlData = new JSONObject(); + stlData.put("billNo", respBizData.getString("payRecordId")); + stlData.put("accountName", respBizData.getString("accountName")); + stlData.put("accountNo", respBizData.getString("accountNo")); + stlData.put("bankName", respBizData.getString("accountBranchBank")); + stlData.put("channelState", respBizData.getString("chnlRespCode")); + stlData.put("remark", respBizData.getString("chnlRespMsg")); + String stlAmt = respBizData.getString("transferMoneyAmount"); + if (StringUtils.isNotBlank(stlAmt)) { + boolean val = stlAmt.contains(","); + if (val) { + stlAmt = stlAmt.replace(",", ""); + } + stlData.put("settleAmt", new BigDecimal(stlAmt).multiply(BigDecimal.valueOf(100))); + } +// String feeAmt = respBizData.getString("feeAmt"); +// if (StringUtils.isNotBlank(feeAmt)) { +// boolean val = feeAmt.contains(","); +// if (val) { +// feeAmt = feeAmt.replace(",", ""); +// } +// long fee = new BigDecimal(feeAmt).multiply(BigDecimal.valueOf(100)).longValue(); +// if( fee > 0L){ +// stlData.put("fee",fee); +// } +// } + String payDate = respBizData.getString("transferMoneyDate"); + stlData.put("settleDate", payDate); + stlData.put("settleTime", payDate + " " + respBizData.getString("transferMoneyTime")); + SettleState state = SettleState.getVal(respBizData.getString("transferMoneyStatus")); + switch (state) { + case PAY_SUCCESS: + stlData.put("state", SettleInfo.SUCCESS); + break; + case PAY_FAIL: + stlData.put("state", SettleInfo.FAIL); + break; + case PAY_PROGRESS: + stlData.put("state", SettleInfo.PROGRESS); + break; + case PAY_EZ: + stlData.put("state", SettleInfo.OTHER); + break; + default: + stlData.put("state", SettleInfo.WAIT); + break; + } + stlData.put("channelState", state.getState()); + stlData.put("extra", respBizData.toString()); + result.add(stlData); + } + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState { + + PAY_INIT("00", "初始登记"), + + PAY_PROGRESS("01", "付款中"), + + PAY_SUCCESS("02", "付款成功"), + + PAY_FAIL("03", "付款失败"), + + PAY_EZ("EZ", "状态未明"), + + PAY_AUDIT("07", "审核中"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state) { + SettleState[] values = values(); + for (SettleState val : values) { + if (val.getState().equals(state)) { + return val; + } + } + return PAY_INIT; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApplymentService.java new file mode 100644 index 0000000..045c3f0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayMchApplymentService.java @@ -0,0 +1,573 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.stream.StreamUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.Lklsb2bpayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.db.entity.BankBranchLkl; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.LocationCacheService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.mapper.BankBranchLklMapper; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bMercInfoConn; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class Lklsb2bpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private LocationCacheService locationCacheService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private BankBranchLklMapper bankBranchLklMapper; + + @Autowired + private Configuration configuration; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public MchApplyment firstApplyment(MchApplyment mchApplyment) { + // 直接丢到异步处理进件逻辑, 通用请求可照此逻辑 + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + result.setState(MchApplyment.STATE_AUDITING_WAIT); + result.setRemainStep((byte) 1); + + Lklsb2bpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), Lklsb2bpayApplymentInfo.class); + applymentInfo.saveCheck(); + + Assert.notNull(applymentInfo.getAreaName(), "经营地区名称[areaName]不能为空"); + Assert.isFalse(applymentInfo.getAreaName().isEmpty(), "经营地区名称[areaName]不能为空"); + + result.setSettlementType(applymentInfo.getSettleType()); + + return result; + } + + private static Lklsb2bMercInfoConn.Attachment getAttachment(Lklsb2bpayIsvParams isvParams, File file, String imgType) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, file, imgType); + Lklsb2bMercInfoConn.Attachment attachmentItem = new Lklsb2bMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private static Lklsb2bMercInfoConn.Attachment getAttachment(Lklsb2bpayIsvParams isvParams, String fileUrl, String imgType) { + JSONObject imgUploadResult = Lklsb2bpayKit.uploadRequest(isvParams, fileUrl, imgType); + Lklsb2bMercInfoConn.Attachment attachmentItem = new Lklsb2bMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private File writeHtml(Template template, Map data) throws IOException, TemplateException { + String fileName = UUID.randomUUID().toString(); + File htmlFile = new File(FileUtil.getTmpDir(), fileName + ".html"); + FileWriter sw = new FileWriter(htmlFile); + log.info("生成协议html, 地址:{}, 参数:{} ", htmlFile.getAbsolutePath(), data); + template.process(data, sw); + + return htmlFile; + } + + private static File createAgreementPicture(File htmlFile) throws IOException { + File outputFile = new File(FileUtil.getTmpDir(), htmlFile.getName() + ".jpg"); + log.info("生成图片开始, HTML地址 {}, 图片地址:{}", htmlFile.getAbsolutePath(), outputFile.getAbsolutePath()); + String commandProcess = "wkhtmltoimage --width 400 --quality 94 " + htmlFile.getPath() + " " + outputFile.getPath(); + log.info("协议执行Process command:{}", commandProcess); + long startTime = System.currentTimeMillis(); //获取开始时间 + Process process = Runtime.getRuntime().exec(commandProcess); + try { + int exitVal = process.waitFor(); + log.info("协议html转换png结果:{}", exitVal); + } catch (InterruptedException e) { + log.info("协议html转换png错误", e); + Thread.currentThread().interrupt(); + throw new IOException(e); + } + long endTime = System.currentTimeMillis(); //获取结束时间 + log.info("程序运行时间: " + (endTime - startTime) + "ms"); + log.info("生成图片结束,地址: {}", outputFile.getPath()); + Thumbnails.of(outputFile).scale(1).outputQuality(0.9).toFile(outputFile); + return outputFile; + } + + private String getEndDate(String endDate) { + if ("长期".equals(endDate)) { + return "2099-12-31"; + } + + return endDate; + } + + private Lklsb2bMercInfoConn getLklData(Lklsb2bpayApplymentInfo applymentInfo, Lklsb2bpayIsvParams isvParams) { + Lklsb2bMercInfoConn mercInfo = new Lklsb2bMercInfoConn(); + mercInfo.setUserNo(Long.parseLong(isvParams.getUserNo())); + mercInfo.setEmail("18062761507@163.com"); + mercInfo.setBusiCode(LklpayConst.BIZ_CODE_B2B); + + if (MchApplyment.MERCHANT_TYPE_PERSONAL == applymentInfo.getMerchantType()) { + mercInfo.setMerType("TP_PERSONAL"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } else { + mercInfo.setMerType("TP_MERCHANT"); + String mchFullName = applymentInfo.getMchFullName(); + if (mchFullName.length() > 20) { + // 字数过长,商户商户全称 + mercInfo.setMerRegName(applymentInfo.getMerRegName()); + } else { + mercInfo.setMerRegName(mchFullName); + } + } + + mercInfo.setMerName(applymentInfo.getMchShortName()); + mercInfo.setMerAddr(applymentInfo.getAddress()); + + mercInfo.setProvinceCode(applymentInfo.getMchAreaCode().getString(0)); + mercInfo.setCityCode(applymentInfo.getMchAreaCode().getString(1)); + mercInfo.setCountyCode(applymentInfo.getMchAreaCode().getString(2)); + + if (1 != applymentInfo.getMerchantType()) { + // 非小微商户提交营业执照信息 + mercInfo.setLicenseName(applymentInfo.getMchFullName()); + mercInfo.setLicenseNo(applymentInfo.getLicenseNo()); + mercInfo.setLicenseDtStart(applymentInfo.getLicenseEffectBegin()); + mercInfo.setLicenseDtEnd(getEndDate(applymentInfo.getLicenseEffectEnd())); + } + // 接口的经纬度字段是反的 + mercInfo.setLatitude(applymentInfo.getLatitude()); + mercInfo.setLongtude(applymentInfo.getLongtude()); + mercInfo.setSource("APP"); + + Assert.notNull(applymentInfo.getMccCode(), "缺少mcc编码信息"); + String[] mccInfo = applymentInfo.getMccCode().split("_"); + if (mccInfo.length != 2) { + throw new BizException("mcc数据异常"); + } + mercInfo.setBusinessContent(mccInfo[0]); + mercInfo.setLarName(applymentInfo.getIdcardName()); + mercInfo.setLarIdType("01"); + mercInfo.setLarIdCard(applymentInfo.getIdcardNo()); + mercInfo.setLarIdCardStart(applymentInfo.getIdcardEffectBegin()); + mercInfo.setLarIdCardEnd(getEndDate(applymentInfo.getIdcardEffectEnd())); + mercInfo.setContactMobile(applymentInfo.getContactPhone()); + mercInfo.setContactName(applymentInfo.getContactName()); + + BankBranchLkl bankCodeLkl = bankBranchLklMapper.selectByContactLine(applymentInfo.getOpenningBankCode()); + Assert.notNull(bankCodeLkl, "未获取到支行信息,请重新选择支行信息"); + + mercInfo.setOpenningBankCode(bankCodeLkl.getContactLine()); + mercInfo.setOpenningBankName(bankCodeLkl.getBranchName()); + mercInfo.setClearingBankCode(bankCodeLkl.getClearNo()); + + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaCode(), "缺少支行地区编码信息"); + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaName(), "缺少支行地区信息"); + mercInfo.setSettleProvinceCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(0)); + mercInfo.setSettleProvinceName(applymentInfo.getSettAccountBankBranchAreaName().getString(0)); + mercInfo.setSettleCityCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(1)); + mercInfo.setSettleCityName(applymentInfo.getSettAccountBankBranchAreaName().getString(1)); + mercInfo.setAccountNo(applymentInfo.getSettAccountNo()); + mercInfo.setAccountName(applymentInfo.getSettAccountName()); + mercInfo.setAccountType(applymentInfo.getSettAccType()); + mercInfo.setAccountIdType("01"); + mercInfo.setAccountIdCard(applymentInfo.getSettAccountIdcardNo()); + mercInfo.setAccountIdDtStart(applymentInfo.getSettAccountIdcardEffectBegin()); + mercInfo.setAccountIdDtEnd(getEndDate(applymentInfo.getSettAccountIdcardEffectEnd())); + + mercInfo.setBizContent(getFeeInfo(applymentInfo, isvParams)); + mercInfo.setSettleType(applymentInfo.getSettleType()); + mercInfo.setSettlementType("AUTOMATIC"); + + return mercInfo; + } + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + private Lklsb2bMercInfoConn.BizContent getFeeInfo(Lklsb2bpayApplymentInfo applymentInfo, Lklsb2bpayIsvParams isvParams) { + Map map = new HashMap<>(); + + List paywayFeeList = applymentInfo.getPaywayFeeList(); + + for (PaywayFee paywayFee : paywayFeeList) { + boolean isYsfLevelFee = (paywayFee.getWayCode().startsWith("YSF_") || paywayFee.getWayCode().startsWith("UP_")) + && PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) + && CollUtil.isNotEmpty(paywayFee.getLevelList()); + if (isYsfLevelFee) { + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + map.put("YSF_DISCOUNT_DEBIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee1)); + + PaywayFee paywayFee2DebitCard = paywayFee.getLevelList().get(1); + double topFee2 = (double) paywayFee2DebitCard.getMaxFee() / 100L; + map.put("DEBIT_CARD", new Lklsb2bMercInfoConn.Fee("DEBIT_CARD", 0.5d, topFee2)); +// map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee2)); + } + + PaywayFee creditCardPaywayFee = paywayFee.getCreditCardPaywayFee(); + if (creditCardPaywayFee != null && CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()) && (CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()))) { + PaywayFee paywayFeeCrebitCard = creditCardPaywayFee.getLevelList().get(0); + map.put("YSF_DISCOUNT_CREDIT_FEE", new Lklsb2bMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFeeCrebitCard.getFeeRate())), null)); + + PaywayFee paywayFee2CrebitCard = creditCardPaywayFee.getLevelList().get(1); + map.put("CREDIT_CARD", new Lklsb2bMercInfoConn.Fee("CREDIT_CARD", Double.parseDouble(convertRate(paywayFee2CrebitCard.getFeeRate())), null)); + + } + + if (paywayFee.getWayCode().startsWith("WX_")) { + map.put("WECHAT", new Lklsb2bMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + + if (paywayFee.getWayCode().startsWith("ALI_")) { + map.put("ALIPAY", new Lklsb2bMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + if ("D0".equals(paywayFee.getWayCode())) { + double d0Rate = Double.parseDouble(convertRate(paywayFee.getFeeRate())); + // 扫码d0费率 + map.put("SCAN_PAY_SECOND", new Lklsb2bMercInfoConn.Fee("SCAN_PAY_SECOND", d0Rate, null)); + // 刷卡D0费率 + map.put("CARD_SECOND", new Lklsb2bMercInfoConn.Fee("CARD_SECOND", d0Rate, null)); + } + } + + // 扫码d0费率 + map.putIfAbsent("SCAN_PAY_SECOND", new Lklsb2bMercInfoConn.Fee("SCAN_PAY_SECOND", 0.1d, null)); + // 刷卡D0费率 + map.putIfAbsent("CARD_SECOND", new Lklsb2bMercInfoConn.Fee("CARD_SECOND", 0.1d, null)); + + Lklsb2bMercInfoConn.BizContent bizContent = new Lklsb2bMercInfoConn.BizContent(); + + String[] mccInfo = applymentInfo.getMccCode().split("_"); + bizContent.setMcc(mccInfo[1]); + // 25为B2B收银台 13位专业扫码 + bizContent.setActivityId(13); + bizContent.setTermNum("1"); + bizContent.setFees(new HashSet<>(map.values())); + + return bizContent; + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + param.put("customerNo", mchApplyment.getChannelApplyNo()); + JSONObject respData = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.AUDIT_STATUS_GET, isvParams, param); + JSONObject customer = respData.getJSONObject("customer"); + JSONArray terminalInfo = respData.getJSONArray("terminalInfo"); + + String status = customer.getString("customerStatus"); + String externalCustomerNo = customer.getString("externalCustomerNo"); + + if ("OPEN".equals(status)) { + JSONArray customerFeeList = respData.getJSONArray("customerFee"); + String termId = null; + // 将对应终端号下的终端id存下来 + for (int i = 0; i < customerFeeList.size(); i++) { + JSONObject customerFee = customerFeeList.getJSONObject(i); + String termNo = customerFee.getString("termNo"); + if (Objects.equals(termNo, customer.getString("termNo"))) { + termId = customerFee.getString("termId"); + break; + } + } + + mchApplyment.setSuccResParameter(customer.toString()); + Optional.ofNullable(termId).ifPresent(t -> customer.put("termId", t)); + + // 进件通过 + mchApplyment.setState(MchApplyment.STATE_SUCCESS); + mchApplyment.setChannelMchNo(externalCustomerNo); + + subMchColl(mchApplyment); + } + + if ("REJECT".equals(status)) { + // 入网驳回 + String auditRemark = customer.getString("auditRemark"); + mchApplyment.setSuccResParameter(customer.toJSONString()); + mchApplyment.setApplyErrorInfo("[" + auditRemark + "]"); + mchApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return mchApplyment; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public void subMchColl(MchApplyment mchApplyment) { + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject respData = Lklsb2bpayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = respData.getJSONArray("list"); + + if (subMercList == null) { + return; + } + + subMercList.forEach(item -> { + if (item instanceof JSONObject) { + JSONObject itemJson = (JSONObject) item; + processItem(itemJson, mchApplyment); + } + }); + } + + private void processItem(JSONObject itemJson, MchApplyment mchApplyment) { + boolean isLklWxSubMch = isLakalaSubMerchant(itemJson) && isWXZFRegisterType(itemJson); + + // 银联商户号 || 拉卡拉微信子商户号 + if ("UNIONPAY".equals(itemJson.getString("registerChannel")) || isLklWxSubMch) { + // 收银呗 + saveSubMerch(mchApplyment.getApplyId(), mchApplyment.getChannelMchNo(), itemJson, 1); + } else { + // 扫码付不存拉卡拉的子商户号 + saveSubMerch(mchApplyment.getApplyId(), mchApplyment.getChannelMchNo(), itemJson, 0); + } + } + + /** + * 是否是拉卡拉的商户号 + */ + private boolean isLakalaSubMerchant(JSONObject itemJson) { + return "38630418".equals(itemJson.getString("channelId")); + } + + /** + * 是否是微信渠道 + */ + private boolean isWXZFRegisterType(JSONObject itemJson) { + return "WXZF".equals(itemJson.getString("registerType")); + } + + private void saveSubMerch(String mchApplyId, String channelMchNo, JSONObject itemJson, Integer isMainUse) { + String resultCode = itemJson.getString("resultCode"); + + MchSubInfoEntity subInfo = new MchSubInfoEntity(); + subInfo.setMchApplyId(mchApplyId); + subInfo.setChannelId(itemJson.getString("channelId")); + subInfo.setSubMchId(itemJson.getString("subMchId")); + subInfo.setRemark(itemJson.getString("resultMessage")); + subInfo.setChannelMchNo(channelMchNo); + subInfo.setMainUse(isMainUse); + subInfo.setSubMchWay(itemJson.getString("registerChannel")); + if ("ZFBZF".equals(itemJson.getString("registerType"))) { + subInfo.setSubMchType("ZFB"); + } else { + subInfo.setSubMchType("WX"); + } + + subInfo.setStatus(resultCode); + + try { + mchSubInfoService.save(subInfo); + } catch (DuplicateKeyException e) { + log.info("对应子商户信息已存在"); + } + } + + @Override + public void subMchCert(MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + if ("WX".equals(mchSubInfo.getSubMchType())) { + wxAuthResult(mchApplyment, mchSubInfo); + } + + if ("ZFB".equals(mchSubInfo.getSubMchType())) { + zfbAuthResult(mchApplyment, mchSubInfo); + } + } + + public void wxAuthResult(MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = StreamUtil.of(subMercList) + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("WXZF")) + .collect(Collectors.toList()); + + // 拉卡拉开放平台商户号 + subMercList.getJSONObject(0); + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + + if (CharSequenceUtil.isEmpty(subMchId)) { + return; + } + + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "WECHAT") + .fluentPut("subMerchantId", subMchId); + + JSONObject respData = Lklsb2bpayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.set(MchSubInfoEntity::getSubMchId, subMchId); + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } + + public void zfbAuthResult(MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + Lklsb2bpayIsvParams isvParams = ((Lklsb2bpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = Lklsb2bpayKit.applymentRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("ZFBZF")) + .collect(Collectors.toList()); + + // 拉卡拉开放平台商户号 + subMercList.getJSONObject(0); + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + + if (CharSequenceUtil.isEmpty(subMchId)) { + return; + } + + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "ALIPAY") + .fluentPut("subMerchantId", subMchId); + + JSONObject respData = Lklsb2bpayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + + if ("AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + +// if ("CLOSED".equals(authorizeState)) { +// ums.setAliCertStatus("-1"); +// } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.set(MchSubInfoEntity::getSubMchId, subMchId); + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderCloseService.java new file mode 100644 index 0000000..58db3a9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderCloseService.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 关闭订单接口实现类 + * + * @author crystal + * + */ +@Slf4j +@Service +public class Lklsb2bpayPayOrderCloseService implements IPayOrderCloseService { + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + try { + JSONObject bizContent = new JSONObject(); + bizContent.put("merchant_no", payOrder.getChannelMchNo()); + bizContent.put("out_order_no", payOrder.getPayOrderId()); + MchApplyment mchApplyment = mchAppConfigContext.getMchApplyment(); + JSONObject respBizData = Lklsb2bpayKit.payRequest(Lklsb2bPayMethod.Api.CASHIER_CLOSE, mchApplyment, bizContent); + String trade_no = respBizData.getString("pay_order_no"); + Lklsb2bOrderStatus order_status = Lklsb2bOrderStatus.getVal(respBizData.getIntValue("order_status")); + switch (order_status){ + case CLOSE: + return ChannelRetMsg.confirmSuccess(trade_no); + } + return ChannelRetMsg.confirmFail(order_status.getDesc()); + }catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderQueryService.java new file mode 100644 index 0000000..3969682 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPayOrderQueryService.java @@ -0,0 +1,58 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bb2bpay; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.LKlsb2bCardType; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉查询订单 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class Lklsb2bpayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg retMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + bizContent.put("out_order_no",payOrder.getPayOrderId()); + bizContent.put("merchant_no",payOrder.getChannelMchNo()); + JSONObject response = Lklsb2bpayKit.payRequest(Lklsb2bPayMethod.Api.CASHIER_QUERY, mchAppConfigContext.getMchApplyment(), bizContent); + retMsg.setChannelBizData(response); + Lklsb2bOrderStatus state = Lklsb2bOrderStatus.getVal(response.getIntValue("order_status")); + JSONArray order_trade_info_list = response.getJSONArray("order_trade_info_list"); + JSONObject bizData = order_trade_info_list.getJSONObject(0); + LKlsb2bCardType acc_type = LKlsb2bCardType.getVal(bizData.getString("acc_type")); + retMsg.setChannelUserId(bizData.getString("user_id2")); + retMsg.setPlatformMchOrderNo(bizData.getString("trade_no")); + retMsg.setChannelOrderId(bizData.getString("log_no")); + retMsg.setPlatformOrderNo(bizData.getString("acc_trade_no")); + retMsg.setDrType(acc_type.getType()); + switch (state){ + case SUCCESS: + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + default: + retMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return retMsg; + } + return retMsg; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPaymentService.java new file mode 100644 index 0000000..70688cc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayPaymentService.java @@ -0,0 +1,101 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + * 拉卡拉支付 + * @author crystal + */ +@Slf4j +@Service +public class Lklsb2bpayPaymentService extends AbstractPaymentService { + + /** + * 拉卡拉花呗分期参数支持选项 + */ + public static final int[] ALI_HB_FQ_NUM_ARR = {3,6,12}; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + @Override + public boolean isSupport(String wayCode) + { + if(CS.PAY_WAY_CODE.CASHIER.equals(wayCode)){ + return true; + } + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + /** + * 统一返回参数解析 + * @param bizData + * @param channelRetMsg + */ + public JSONObject initResult(JSONObject bizData, ChannelRetMsg channelRetMsg) { + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelBizData(bizData); + if(Lklsb2bPayMethod.NeedQuery.NO.getStatus().equals(bizData.getString("need_query"))){ + channelRetMsg.setNeedQuery(false); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + channelRetMsg.setChannelOrderId(bizData.getString("log_no")); + channelRetMsg.setPlatformOrderNo(bizData.getString("acc_trade_no")); + channelRetMsg.setPlatformMchOrderNo(bizData.getString("trade_no")); + JSONObject acc_resp_fields = bizData.getJSONObject("acc_resp_fields"); + if(acc_resp_fields != null){ + String userId = StringUtils.isNotEmpty(acc_resp_fields.getString("user_id")) ? acc_resp_fields.getString("user_id") : acc_resp_fields.getString("open_id"); + channelRetMsg.setChannelUserId(userId); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(acc_resp_fields.getString("prepay_id")); + jsapiMsg.setAppId(acc_resp_fields.getString("app_id")); + jsapiMsg.setPaySign(acc_resp_fields.getString("pay_sign")); + jsapiMsg.setTimeStamp(acc_resp_fields.getString("time_stamp")); + jsapiMsg.setNonceStr(acc_resp_fields.getString("nonce_str")); + jsapiMsg.setPayPackage(acc_resp_fields.getString("package")); + jsapiMsg.setSignType(acc_resp_fields.getString("sign_type")); + jsapiMsg.setRedirectUrl(acc_resp_fields.getString("redirect_url")); + channelRetMsg.setJsapiMsg(jsapiMsg); + } + return acc_resp_fields; + } + + public void preCheckAli(UnifiedOrderRQ rq) { + Integer hbFqNum = rq.getHbFqNum(); + if(hbFqNum != null){ + boolean isCheck = Arrays.stream(ALI_HB_FQ_NUM_ARR).anyMatch(num -> num == hbFqNum); + if(!isCheck){ + throw new BizException("支付宝支付花呗分期参数有误,仅可支持数值为"+StringUtils.join(ALI_HB_FQ_NUM_ARR,",") +"期"); + } + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayRefundService.java new file mode 100644 index 0000000..a39f547 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/Lklsb2bpayRefundService.java @@ -0,0 +1,112 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.BizException; +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; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +/** + * 退款接口: 拉卡拉 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class Lklsb2bpayRefundService extends AbstractRefundService { + + @Autowired + private MchApplymentService mchApplymentService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSB2BPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + ChannelRefundLimit refundLimit = this.isRefundLimit(payOrder.getSettleType(), payOrder.getMchExtNo()); + if(refundLimit.getIsPlatAccount()){ + if(ChannelRefundLimit.NO_OPEN == refundLimit.getBindStatus()){ + throw new BizException("拉卡拉通道D0退款需要先申请平台户退款"); + }else{ + this.checkPlatAccount(refundOrder); + } + } + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizData = new JSONObject(); + bizData.put("merchant_no",payOrder.getChannelMchNo()); + bizData.put("out_trade_no",refundOrder.getRefundOrderId()); + bizData.put("origin_trade_no",refundOrder.getPayOrderId()); + String channelBizData = payOrder.getChannelBizData(); + if(StringUtils.isNotEmpty(channelBizData)){ + JSONObject channelData = JSON.parseObject(channelBizData); + bizData.put("term_no",channelData.getString("term_no")); + } + bizData.put("refund_amount",refundOrder.getRefundAmount()); + bizData.put("refund_reason",refundOrder.getRefundReason()); + bizData.put("origin_trade_no",payOrder.getPlatformOrderNo()); + JSONObject location_info = new JSONObject(); + location_info.put("request_ip",refundOrder.getClientIp()); + bizData.put("location_info",location_info); + JSONObject respBizData = Lklsb2bpayKit.payRequest(Lklsb2bPayMethod.Api.ORDER_REFUND, mchAppConfigContext.getMchApplyment(), bizData); + channelRetMsg.setChannelBizData(respBizData); + channelRetMsg.setChannelOrderId(respBizData.getString("log_no")); + channelRetMsg.setPlatformMchOrderNo(respBizData.getString("trade_no")); + channelRetMsg.setPlatformOrderNo(respBizData.getString("acc_trade_no")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + return channelRetMsg; + } + + /** + * 退款权限 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + ChannelRefundLimit channelRefundLimit = new ChannelRefundLimit(false,true); + if(CS.SETTLEMENT_TYPE.D0.equals(settleType)){ + channelRefundLimit.setIsDefaultAccount(false); + channelRefundLimit.setIsPlatAccount(true); + MchApplyment applyment = mchApplymentService.getById(applyId); + if(MchApplyment.REFUND_WAY_PLATFORM.equals(applyment.getRefundWay())){ + channelRefundLimit.setBindStatus(ChannelRefundLimit.SUCCESS); + }else{ + channelRefundLimit.setBindStatus(ChannelRefundLimit.NO_OPEN); + } + } + return channelRefundLimit; + } + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + super.checkPlatAccount(refundOrder); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/README.MD b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/README.MD new file mode 100644 index 0000000..2fa0265 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/README.MD @@ -0,0 +1,6 @@ +## 使用汇拓客进件 + +拉卡拉汇拓客使用汇拓客的代码进行发起进件,使用拉卡拉开放平台的接口进行交易。 +故此代码中的支付代码与外部lklpay包中的交易服务代码是一致的。 + +此方式使用b2b收银台 diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/ILklTkReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/ILklTkReqMethod.java new file mode 100644 index 0000000..7972a5f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/ILklTkReqMethod.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import lombok.Getter; +import org.springframework.http.MediaType; + +@Getter +public abstract class ILklTkReqMethod { + + protected ILklTkReqMethod(String url, String templateWord, String method, String urlFlag) { + this(url, templateWord, method, false, urlFlag); + } + + protected ILklTkReqMethod(String url, String templateWord, String method, boolean encrypt, String urlFlag) { + this.url = url; + this.templateWord = templateWord; + this.method = method; + if (method.equals(LklpayConst.GET)) { + this.contentType = MediaType.APPLICATION_FORM_URLENCODED; + } else { + this.contentType = MediaType.APPLICATION_JSON; + } + this.encrypt = encrypt; + this.urlFlag = urlFlag; + } + + protected ILklTkReqMethod(String url, String templateWord, String method, MediaType contentType) { + this(url, templateWord, method, contentType, false); + } + + protected ILklTkReqMethod(String url, String templateWord, String method, MediaType contentType, boolean encrypt) { + this.url = url; + this.templateWord = templateWord; + this.method = method; + this.contentType = contentType; + this.encrypt = encrypt; + this.urlFlag = "saas"; + } + + private final String url; + + private final String templateWord; + + /** + * get或者post + */ + private final String method; + + private final MediaType contentType; + + private final boolean encrypt; + + /** + * 有saas和open两种 + */ + private final String urlFlag; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LKlsb2bCardType.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LKlsb2bCardType.java new file mode 100644 index 0000000..107bbcb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LKlsb2bCardType.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉交易卡类型枚举 + * @author crystal + * @date 2023/6/7 10:19 + */ +@Getter +@AllArgsConstructor +public enum LKlsb2bCardType { + + DEBIT("00","借记卡"), + + CREDIT("01","贷记卡"), + + BALANCE("02","零钱"), + + TOKIO("03","花呗"), + + ALI_OTHER("04","支付宝其他"), + + DECP("05","数字货币"), + + LKL_ACCOUNT("06","拉卡拉账户"), + + UNKNOWN("99","未知"); + + private final String type; + + private final String desc; + + public static LKlsb2bCardType getVal(String type){ + LKlsb2bCardType[] values = values(); + for (LKlsb2bCardType val:values) { + if(val.getType().equals(type)){ + return val; + } + } + return UNKNOWN; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LklTkReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LklTkReqMethod.java new file mode 100644 index 0000000..c67f642 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/LklTkReqMethod.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + + +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst; +import org.springframework.http.MediaType; + +import static com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util.Lklsb2bpayConst.*; + +public final class LklTkReqMethod extends ILklTkReqMethod { + + /** + * 拉卡拉平台公钥 + */ + public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXCrnI36j2nBpZhbHvgrMZdsGOYSWigvuVaDm/FEHPcQJJsYrs/eK3Vs7XtFSezaIf95r+YD0fewLOgw31FuZOcraf5P0I/BGuvpWfstwuI28UfzNld+XzXy0YHsmo010VgwkGJrKFezQHjKD85HT57iBoEQiUt+00+X0D/rJ2MQIDAQAB"; + + /** + * 拉卡拉roshang机构私钥 + */ + public static final String PRI_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJcKucjfqPacGlmFse+Csxl2wY5hJaKC+5VoOb8UQc9xAkmxiuz94rdWzte0VJ7Noh/3mv5gPR97As6DDfUW5k5ytp/k/Qj8Ea6+lZ+y3C4jbxR/M2V35fNfLRgeyajTXRWDCQYmsoV7NAeMoPzkdPnuIGgRCJS37TT5fQP+snYxAgMBAAECgYEAiKF3NjK8kXjcjSbXsyW0BdDbfoR6muuJ0bmaozMb5R8BRtCIL6HquJaaPZ4u/gheJDTDzGAaaqPIAi+jLJYudlPvKVClncKsunLNpwxwAQdZfs2r82GWaW67AwtM3JZ9U2bqfQ8ckQreIlJRlGQYcCpeuH+WNLztC4XAeo9UPxECQQD1OYARwLzdClin43S02pee/niiIiZW6rQcPJ1MtLfc0Dt5+342M+tBlGPvJ2vLWAyD4yvv7siLBdztvS4hABVbAkEAna3GwAzSQqtADPQkWbYmv3ell3sOHonJUWUQPM+OlIBoOVJ3gY/Jx47CKzLSsWLl+b8P4jvBJE+4sT1srPDcYwJAISImyr9HBXq7ZdvWzgTnDaWGeSmyEnZd5Z7PBik42o4MKzwu3nX/aHn7Urn515zK/Br6uc2CrT4ajsjL7cuMFwJBAJwBtaWKifYgjazDWbvRNyE1dgccX2njleYMgjZIfZ98NKKSb18nLtNc8cvf6wpK+ZNScJq72Gre3bOvPHkXjlUCQQDDKI/vYWivIzOS71wRO3nfajr3tIPHyHp7drxWMlqblohsWr7PTZ3RVvLza4PXx2uVgtPkMOKUHlXolj4U3mpQ"; + + public static final ILklTkReqMethod TOKEN_AUDIT = new LklTkReqMethod("https://tkapi.lakala.com/auth/oauth/token", null, POST, MediaType.APPLICATION_FORM_URLENCODED); + public static final ILklTkReqMethod AUDIT = new LklTkReqMethod("https://htkactvi.lakala.com/registration/merchant", null, POST); + public static final ILklTkReqMethod SUB_MERC_LIST = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/submer", null, POST, true); + + public static final ILklTkReqMethod AUDIT_STATUS_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/info", null, POST, true); + public static final ILklTkReqMethod TOKEN_EDIT = new LklTkReqMethod("https://htkapi.lakala.com/auth/oauth/token", null, POST, MediaType.APPLICATION_FORM_URLENCODED); + public static final ILklTkReqMethod RATE_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/fee/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, GET); + public static final ILklTkReqMethod RATE_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/fee/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, POST, EDIT); + public static final ILklTkReqMethod SETTLE_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/settle/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, GET); + public static final ILklTkReqMethod SETTLE_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/settle/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, POST); + public static final ILklTkReqMethod BASE_INFO_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/basic", null, POST, EDIT); + public static final ILklTkReqMethod CHANGE_STATUS_GET = new LklTkReqMethod("https://htkapi.lakala.com/api/customer/update/review", null, GET, EDIT); + public static final ILklTkReqMethod UPLOAD = new LklTkReqMethod("https://htkactvi.lakala.com/registration/file/upload", null, POST); + + public static final ILklTkReqMethod ADD_TERM = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/addTerm", null, POST); + public static final ILklTkReqMethod MCH_AUTH_STATUS = new LklTkReqMethod("https://s2.lakala.com/api/v2/mms/sme/mrchAuthStateQuery", null, POST); + + /** + * 拉卡拉开放平台接口,用于查询汇拓客对应的开放平台子商户号 + */ + public static final ILklTkReqMethod QUERY_SUB_MERC = new LklTkReqMethod("https://s2.lakala.com/api/v2/mms/openApi/querySubMerInfo", null, POST); + + /** + * 复议提交 + */ + public static final ILklTkReqMethod AUDIT_RETRY = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/reconsider/submit", null, POST); + + private LklTkReqMethod(String url, String templateWord, String method, MediaType contentType) { + super(url, templateWord, method, contentType); + } + + + private LklTkReqMethod(String url, String templateWord, String method) { + super(url, templateWord, method, Lklsb2bpayConst.AUDIT); + } + + private LklTkReqMethod(String url, String templateWord, String method, String urlFlag) { + super(url, templateWord, method, urlFlag); + } + + private LklTkReqMethod(String url, String templateWord, String method, boolean encrypt) { + super(url, templateWord, method, encrypt, Lklsb2bpayConst.AUDIT); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklb2bMchReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklb2bMchReq.java new file mode 100644 index 0000000..7f32d91 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklb2bMchReq.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.util.UUID; + +/** + * TODO + * 拉卡拉用户id相关操作 + * @author crystal + * @date 2023/11/25 15:39 + */ +@Data +public class Lklb2bMchReq { + + private String timestamp; + + private String rnd; + + private String ver; + + private String reqId; + + private JSONObject reqData; + + public Lklb2bMchReq(JSONObject reqData) { + this.timestamp = System.currentTimeMillis() + ""; + this.rnd = UUID.randomUUID().toString().replace("-",""); + this.reqId = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_MS_PATTERN); + this.ver = "1.0.0"; + this.reqData = reqData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bMercInfoConn.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bMercInfoConn.java new file mode 100644 index 0000000..b5a81a2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bMercInfoConn.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.util.Set; + +@Setter +@Getter +public class Lklsb2bMercInfoConn { + private Long userNo; + private String email; + private String busiCode; + private String merchantCode; + private String merRegName; + private String merType; + private String merName; + private String merAddr; + private String provinceCode; + private String cityCode; + private String countyCode; + private String licenseName; + private String licenseNo; + private String licenseDtStart; + private String licenseDtEnd; + private String latitude; + private String longtude; + private String source; + private String businessContent; + private String larName; + private String larIdType; + private String larIdCard; + private String larIdCardStart; + private String larIdCardEnd; + private String contactMobile; + private String contactName; + + private String openningBankCode; + + private String openningBankName; + + private String clearingBankCode; + + private String settleProvinceCode; + + private String settleProvinceName; + + private String settleCityCode; + + private String settleCityName; + + private String accountNo; + + private String accountName; + + private String accountType; + + private String accountIdCard; + + private String accountIdDtStart; + + private String accountIdDtEnd; + + private String accountIdType; + + private BizContent bizContent; + + private Set attchments; + private String settleType; + private String shopId; + private String settlementType; + private String regularSettlementTime; + + @Getter + @Setter + public static class BizContent { + + private String termNum; + + private Set fees; + + private String mcc; + + private Integer activityId; + } + + @Getter + @Setter + @AllArgsConstructor + public static class Fee { + + private String feeCode; + + private Double feeValue; + + private Double topFee; + + public Fee(String feeCode, String feeValue, Double topFee) { + this.feeValue = Double.parseDouble(feeValue); + this.feeCode = feeCode; + this.topFee = topFee; + } + } + + @Getter + @Setter + public static class Attachment { + + private String id; + + private String type; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bOrderStatus.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bOrderStatus.java new file mode 100644 index 0000000..8a41359 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bOrderStatus.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉订单状态枚举 + * @author crystal + * @date 2023/11/25 13:58 + */ +@Getter +@AllArgsConstructor +public enum Lklsb2bOrderStatus { + + WAIT(0,"待支付"), + PAYING(1,"支付中"), + SUCCESS(2,"支付成功"), + FAIL(3,"支付失败"), + EXPIRE(4,"已过期"), + CANCEL(5,"已取消"), + PART_REFUND(6,"已退款"), + CLOSE(7,"订单关闭"); + + private final int status; + + private final String desc; + + public static Lklsb2bOrderStatus getVal(Integer status) { + Lklsb2bOrderStatus[] orderStatuses = values(); + for (Lklsb2bOrderStatus orderStatuse : orderStatuses) { + if (status == orderStatuse.getStatus()) { + return orderStatuse; + } + } + return WAIT; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayMethod.java new file mode 100644 index 0000000..35e0901 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayMethod.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2023/6/2 18:17 + */ +public class Lklsb2bPayMethod { + + public static final String DOMAIN = "https://s2.lakala.com"; + + /** + * 拉卡支付路径配置 + */ + @Getter + @AllArgsConstructor + public enum Api{ + TRANS_PREORDER(DOMAIN + "/api/v3/labs/trans/preorder","聚合主扫"), + TRANS_MICROPAY(DOMAIN + "/api/v3/labs/trans/micropay","聚合被扫"), + TRANS_QUERY(DOMAIN + "/api/v3/labs/query/tradequery","聚合扫码-交易查询"), + ORDER_CLOSE(DOMAIN + "/api/v3/labs/relation/close","聚合扫码-关单"), + ORDER_REVOKED(DOMAIN + "/api/v3/labs/relation/revoked","扫码-撤销"), + ORDER_REFUND(DOMAIN + "/api/v3/labs/relation/refund","扫码-退款交易"), + IDM_REFUND(DOMAIN + "/api/v3/labs/relation/idmrefund","商户订单退款"), + IDM_REFUND_QUERY(DOMAIN + "/api/v3/labs/query/idmrefundquery","商户订单退款查询"), + USERID_QUERY(DOMAIN + "/api/v2/saas/query/wx_openid_query","获取用户ID"), + + CASHIER_ORDER(DOMAIN + "/api/v3/ccss/counter/order/create","聚合收银台"), + CASHIER_QUERY(DOMAIN + "/api/v3/ccss/counter/order/query","聚合收银台订单查询"), + CASHIER_CLOSE(DOMAIN + "/api/v3/ccss/counter/order/close","聚合收银台订单关闭"), + + MERC_LEDGER_OPEN(DOMAIN + "/api/v2/mms/openApi/ledger/applyLedgerMer","商户分账申请开通"), + MERC_LEDGER_CHANGE(DOMAIN + "/api/v2/mms/openApi/ledger/modifyLedgerMer","商户分账信息变更"), + MERC_LEDGER_QUERY(DOMAIN + "/api/v2/mms/openApi/ledger/queryLedgerMer","商户分账信息查询"), + + SETTLE_QUERY(DOMAIN + "/api/v2/searcher/transferMoney/queryTransferMoney","结算信息查询"), + + ORDER_FEE_QUERY(DOMAIN + "/api/v3/lams/merchant/query_trans","商户计费查询"), + UPLOAD(DOMAIN + "/api/v2/mms/openApi/uploadFile","附件上传"), + + UNIFY_REFUND(DOMAIN + "/api/v3/lams/trade/trade_refund","统一退货"), + UNIFY_REFUND_QUERY(DOMAIN + "/api/v3/lams/trade/trade_refund_query","退货查询"), + WECHAT_PARAMS_CONFIG_URL(DOMAIN + "/api/v2/mms/openApi/wechatParamConf","微信参数配置"), + + DEVICE_SPEAKER_BOX_ACTIVATE_URL(DOMAIN + "/api/v2/iot/cloud/device/activate","码牌音响激活"), + DEVICE_SPEAKER_BOX_DEACTIVATE_URL(DOMAIN + "/api/v2/iot/cloud/device/deactivate","码牌音响反激活"), + DEVICE_SPEAKER_BOX_ACTIVATE_STATUS_QUERY_URL(DOMAIN + "/api/v2/iot/cloud/device/activate/status","码牌音箱激活状态查询"), + DEVICE_SPEAKER_BOX_PUSH_QRCODE_URL(DOMAIN + "/api/v2/iot/cloud/pushQrcode","推送收款二维码至设备"), + DEVICE_SPEAKER_BOX_QUERY_SN_URL(DOMAIN + "/v2/iot/cloud/query/activate/by/mt","商终查询激活的SN"), + ; + + private final String url; + private final String desc; + } + + + @Getter + @AllArgsConstructor + public enum NeedQuery{ + YES("1","订单处理中需要查询"), + NO("0","不需要主动查询"),; + private final String status; + private final String desc; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayThirdReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayThirdReq.java new file mode 100644 index 0000000..ace13ea --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bPayThirdReq.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * 拉卡拉公共支付请求参数 + * @author crystal + * @date 2023/6/2 17:48 + */ +@Data +@NoArgsConstructor +public class Lklsb2bPayThirdReq { + + public static final String VERSION = "3.0"; + + /** + * 请求时间,格式yyyyMMddHHmmss + */ + private String req_time; + + /** + * 3.0 + */ + private String version; + + /** + * 开放平台APPID + */ + private String out_org_code; + + /** + * 参见各个接口的请求参数格式 + */ + private Object req_data; + + public Lklsb2bPayThirdReq(String out_org_code , Object req_data) { + this(out_org_code,VERSION); + this.req_data = req_data; + } + + public Lklsb2bPayThirdReq(String out_org_code , String version, Object req_data) { + this(out_org_code,version); + this.req_data = req_data; + } + + public Lklsb2bPayThirdReq(String out_org_code, String version) { + this.out_org_code = out_org_code; + this.version = version; + this.req_time = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_FORMAT); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bSettleReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bSettleReq.java new file mode 100644 index 0000000..c293b2c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bSettleReq.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +/** + * TODO + * 拉卡拉结算信息请求参数封装 + * @author crystal + * @date 2023/12/7 11:16 + */ +@Data +public class Lklsb2bSettleReq { + + private Long timestamp; + + private String ver; + + private String reqId; + + private JSONObject reqData; + + public Lklsb2bSettleReq(JSONObject bizData) { + this.timestamp = System.currentTimeMillis(); + this.reqId = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_MS_PATTERN); + this.ver = "1.0.0"; + this.reqData = bizData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bTradeStatus.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bTradeStatus.java new file mode 100644 index 0000000..f281b4f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/model/Lklsb2bTradeStatus.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉交易状态枚举 + * @author crystal + * @date 2023/6/7 10:19 + */ +@Getter +@AllArgsConstructor +public enum Lklsb2bTradeStatus { + + PROCESSING("P","处理中"), + + RECT("C","被冲正"), + + SUCCESS("S","交易成功"), + + FAIL("F","交易失败"), + + SEND_FAIL("X","发送失败"), + + EXPIRE("T","发送超时"); + + private final String tradeStatus; + + private final String desc; + + public static Lklsb2bTradeStatus getVal(String tradeStatus){ + Lklsb2bTradeStatus[] values = values(); + for (Lklsb2bTradeStatus val:values) { + if(val.getTradeStatus().equals(tradeStatus)){ + return val; + } + } + return PROCESSING; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/payway/Cashier.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/payway/Cashier.java new file mode 100644 index 0000000..d4d07bc --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/payway/Cashier.java @@ -0,0 +1,122 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.URLUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.*; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.Lklsb2bpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.ILklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.model.Lklsb2bPayMethod; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +/** + * TODO + * 收银台(B2B) + * @author crystal + * @date 2024/4/22 18:36 + */ +@Service("lklsb2bpayPaymentByCashierService") +public class Cashier extends Lklsb2bpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]参数不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + /** + * 渠道收银台 + * @param rq + * @param payOrder + * @param mchAppConfigContext + * @return + * @throws Exception + */ + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelCashierOrderRS res = ApiResBuilder.buildSuccess(ChannelCashierOrderRS.class); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + res.setChannelRetMsg(retMsg); + ChannelCashierOrderRQ bizRQ = (ChannelCashierOrderRQ) rq; + JSONObject bizData = new JSONObject(); + bizData.put("merchant_no",payOrder.getChannelMchNo()); + bizData.put("total_amount",payOrder.getFindAmt()); + bizData.put("settle_type","0"); + bizData.put("notify_url", getNotifyUrl()); + bizData.put("out_order_no",payOrder.getPayOrderId()); + bizData.put("order_info",payOrder.getSubject()); + bizData.put("order_efficient_time", DateUtil.format(payOrder.getExpiredTime(), DatePattern.PURE_DATETIME_PATTERN)); + bizData.put("callback_url",payOrder.getReturnUrl()); + bizData.put("counter_remark",payOrder.getBuyerRemark()); + Integer hbFqNum = bizRQ.getHbFqNum(); + if(hbFqNum != null){ + JSONObject order_scene_field = new JSONObject(2); + order_scene_field.put("order_scene_type","HB_FQ"); + JSONObject scene_info = new JSONObject(2); + scene_info.put("hbFqNum",hbFqNum); + //间连只支持0 + scene_info.put("hbFqSellerPercent",0); + order_scene_field.put("scene_info",scene_info); + bizData.put("order_scene_field",order_scene_field); + } + //支持退款 + bizData.put("support_refund","1"); + //支持多次支付 + bizData.put("support_repeat_pay","1"); + //TODO 针对多次支付的订单 增加以下处理 repeat_pay_auto_refund 0:重复支付后不自动退货 1:重复支付后自动退货 + bizData.put("repeat_pay_auto_refund","1"); + //TODO 针对多次支付的订单 增加以下处理 repeat_pay_notify 0:重复支付订单不通知;1:重复支付订单通知 + bizData.put("repeat_pay_notify","0"); + //TODO 针对多次支付的订单 增加以下处理 close_order_auto_refund 0:不自动退货;1:关闭订单后支付成功触发自动退货 + bizData.put("close_order_auto_refund","1"); + JSONObject respBizData = Lklsb2bpayKit.payRequest(Lklsb2bPayMethod.Api.CASHIER_ORDER, mchAppConfigContext.getMchApplyment(), bizData); + String counter_url = respBizData.getString("counter_url"); + retMsg.setChannelBizData(respBizData); + retMsg.setChannelOrderId(respBizData.getString("pay_order_no")); + res.setPayUrl(counter_url); + bulidLitePayInfo(res); + return res; + } + + public void bulidLitePayInfo(ChannelCashierOrderRS res) { + ChannelAppletPayMsg payMsg = new ChannelAppletPayMsg(); + // 默认为:拉卡拉聚合收银台小程序的appId + String appId = "wx889424d565967811"; + String ghId = "gh_a73225dbbe6b"; + if (res.getPayUrl().contains("q.huijingcai.top") || res.getPayUrl().contains("q.lakala.com")) { + // 拉卡拉收款宝小程序appId + appId = "wxc3e4d1682da3053c"; + ghId = "gh_3ca1d7144083"; + } + String path = "payment-cashier/pages/checkout/index?source=WECHATMINI&counterUrl=" + URLUtil.encode(res.getPayUrl()); + payMsg.setAppId(appId); + payMsg.setPath(path); + payMsg.setGhId(ghId); + res.getChannelRetMsg().setLiteMsg(payMsg); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/util/Lklsb2bpayConst.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/util/Lklsb2bpayConst.java new file mode 100644 index 0000000..dc4ba9f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklsb2bpay/util/Lklsb2bpayConst.java @@ -0,0 +1,53 @@ +package com.jeequan.jeepay.thirdparty.channel.lklsb2bpay.util; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Lklsb2bpayConst { + + public static final Integer ACTIVITY_ID_WECHAT_PAY = 13; + + public static final Integer ACTIVITY_ID_B2B_SYT = 13; + + /** + * 专业扫码 + */ + public static final String BIZ_CODE_SCAN = "WECHAT_PAY"; + + /** + * B2B收银台 + */ + public static final String BIZ_CODE_B2B = "B2B_SYT"; + + public static final String POST = "POST"; + + public static final String GET = "GET"; + + public static final String AUDIT = "audit"; + public static final String EDIT = "edit"; + + public static final String CUSTOMER_NO_PLACE_HOLDER = "{customerNo}"; + + public static final String CUSTOMER_NO = "customerNo"; + + public static final String REVIEW_RELATED_ID = "reviewRelatedId"; + + public static final String ACCOUNT_NAME = "accountName"; + + public static final String ACCOUNT_NO = "accountNo"; + + public static final String BANK_NAME = "bankName"; + public static final String BANK_NO = "bankNo"; + public static final String CLEARING_BANK_NO = "clearingBankNo"; + + /** + * 变更通过 + */ + public static final String EDIT_PASS = "PASS"; + + /** + * 变更不通过 + */ + public static final String EDIT_UNPASS = "UNPASS"; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelNoticeService.java new file mode 100644 index 0000000..9ff1707 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelNoticeService.java @@ -0,0 +1,94 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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 com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.kqpay.KqpayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LKlCardType; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTradeStatus; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 拉卡拉通知 回调接口实现类 + * + * @author crystal + */ +@Service +@Slf4j +public class LklspayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + JSONObject reqParamJSON = getReqParamJSON(); + String parOrderId = reqParamJSON.getString("out_trade_no"); + return MutablePair.of(parOrderId, reqParamJSON); + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + JSONObject respJson = (JSONObject) JSONObject.toJSON(params); + log.info("拉卡拉回调参数:{}",respJson); + //验签成功后判断上游订单状态 + ResponseEntity okResponse = jsonResp(LklspayKit.ok()); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); +// result.setChannelOriginResponse(respJson.toString()); + result.setPlatformMchOrderNo(respJson.getString("trade_no")); + result.setChannelOrderId(respJson.getString("log_no")); + result.setPlatformOrderNo(respJson.getString("acc_trade_no")); + result.setChannelUserId(respJson.getString("user_id2")); + LklTradeStatus tradeStatus = LklTradeStatus.getVal(respJson.getString("trade_status")); + LKlCardType card_type = LKlCardType.getVal(respJson.getString("card_type")); + String drType = card_type.getType(); + switch (card_type){ + case LKL_ACCOUNT: + case ALI_OTHER: + drType = CS.DrType.OTHER.getType(); + break; + case DECP: + drType = CS.DrType.DCEP.getType(); + break; + } + switch (tradeStatus){ + case FAIL: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case UNKNOWN: + result.setChannelState(ChannelRetMsg.ChannelState.UNKNOWN); + break; + default: + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + } + result.setDrType(drType); + return result; + } + + + /** + * 验证银盛支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + return KqpayKit.checkResultNotify(jsonParams,mchAppConfigContext); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelUserService.java new file mode 100644 index 0000000..3b59eea --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayChannelUserService.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉 获取银联userId实现类 + * + * @author jmdhapy + * + * @date 2022/3/17 16:51 + */ +@Service +@Slf4j +public class LklspayChannelUserService implements IChannelUserService { + + @Autowired + protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("redirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【拉卡拉获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + log.info("{} userAuthCode={}, appUpIdentifier={}", logPrefix, userAuthCode, appUpIdentifier); + JSONObject bizContent = new JSONObject(); + // 用户授权码 + bizContent.put("authCode", userAuthCode); + // 银联支付标识 + bizContent.put("appUpIdentifier", appUpIdentifier); + + MchApplyment mchApplyment = mchAppConfigContext.getMchApplyment(); + LklspayIsvParams isvParams = (LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject respBizData = LklspayKit.reqMch(LklPayMethod.Api.USERID_QUERY, isvParams, bizContent); + return respBizData.getString("userId"); + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayDivisionService.java new file mode 100644 index 0000000..b411967 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayDivisionService.java @@ -0,0 +1,63 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 分账接口 + * + * @author xiaoyu + * + * @date 2023/8/9 8:45 + */ +@Slf4j +@Service +public class LklspayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..d1a2d33 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchAlipayConfigService.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class LklspayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + LklspayIsvParams isvParams = (LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = LklspayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("ZFBZF")) + .collect(Collectors.toList()); + + if (!filteredMercList.isEmpty()) { + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + result.setChannelSubMchId(subMchId); + } + + uWrapper.eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, "ZFB"); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getAliChannelExtUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (result.getChannelSubMchId() != null) { + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "ALIPAY") + .fluentPut("subMerchantId", result.getChannelSubMchId()); + + JSONObject respData = LklspayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState) + || "UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + result.setState("未授权"); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState) + || "AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + result.setState("已授权"); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + + mchSubInfoService.update(null, uWrapper); + } + + + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..25a4e75 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchApplymentNotifyService.java @@ -0,0 +1,267 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklspay.util.LklspayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; +import java.util.Optional; + +@Slf4j +@Service("lklspayIsvmchApplymentNotifyService") +public class LklspayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private LklspayMchApplymentService lklspayMchApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public ResponseEntity retOk(Object params) { + return ResponseEntity.ok("success"); + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + + log.info("拉卡拉进件回调原始参数:{}", reqParamJSON); + RSA rsa = SecureUtil.rsa(null, LklspayIsvParams.PUB_KEY); + String decryptData = rsa.decryptStr(reqParamJSON.getString("data"), KeyType.PublicKey); + log.info("拉卡拉进件回调解密参数: {}", decryptData); + + JSONObject bizJSON = JSON.parseObject(decryptData); + + String reviewRelatedId = bizJSON.getString(LklspayConst.REVIEW_RELATED_ID); + String customerNo = bizJSON.getString(LklspayConst.CUSTOMER_NO); + + if (!ObjectUtils.isEmpty(customerNo)) { + // 进件 + MchApplyment tbMchApplyment = mchApplymentService.getByOrderId(customerNo); + if (tbMchApplyment != null) { + return MutablePair.of(tbMchApplyment.getApplyId(), bizJSON); + } + } + + if (!ObjectUtils.isEmpty(reviewRelatedId)) { + // 变更 + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(reviewRelatedId, CS.IF_CODE.LKLSPAY); + if (mchModifyApplyment != null) { + return MutablePair.of(mchModifyApplyment.getApplyId(), bizJSON); + } + } + + return null; + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + JSONObject bizJSON = (JSONObject) params; + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String reviewRelatedId = bizJSON.getString(LklspayConst.REVIEW_RELATED_ID); + String customerNo = bizJSON.getString(LklspayConst.CUSTOMER_NO); + + if (!ObjectUtils.isEmpty(customerNo)) { + // 进件回调处理 + return doAuditNotify(bizJSON, mchApplyment, isvParams); + } + + if (!ObjectUtils.isEmpty(reviewRelatedId)) { + // 变更回调处理 + return doModifyNotify(reviewRelatedId, mchApplyment, bizJSON); + } + + return MutablePair.of(null, retOk(null)); + } + + public MutablePair doAuditNotify( + JSONObject bizJSON, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, LklspayIsvParams isvParams) { + String status = bizJSON.getString("status"); + String remark = bizJSON.getString("remark"); + + mchApplyment.setRemark(remark); + + // 进件 + if ("SUCCESS".equals(status)) { + JSONObject param = new JSONObject(); + param.put("customerNo", mchApplyment.getChannelApplyNo()); + JSONObject respData = LklspayKit.applymentRequest(LklTkReqMethod.AUDIT_STATUS_GET, isvParams, param); + + JSONObject customer = respData.getJSONObject("customer"); + JSONArray customerFeeList = respData.getJSONArray("customerFee"); + String termId = null; + // 将对应终端号下的终端id存下来 + for (int i = 0; i < customerFeeList.size(); i++) { + JSONObject customerFee = customerFeeList.getJSONObject(i); + String termNo = customerFee.getString("termNo"); + if (Objects.equals(termNo, customer.getString("termNo"))) { + termId = customerFee.getString("termId"); + break; + } + } + + String externalCustomerNo = customer.getString("externalCustomerNo"); + mchApplyment.setChannelMchNo(externalCustomerNo); + mchApplyment.setSuccResParameter(customer.toString()); + Optional.ofNullable(termId).ifPresent(t -> customer.put("termId", t)); + + lklspayMchApplymentService.subMchColl(mchApplyment); + // 进件通过 + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS); + + return MutablePair.of(mchApplyment, retOk(null)); + } else { + mchApplyment.setApplyErrorInfo(remark); + } + + String[] failStatusList = new String[]{ + "COMMIT_FAIL", + "FAILURE", + "INNER_CHECK_REJECTED" + }; + + if (ArrayUtil.contains(failStatusList, status)) { + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return MutablePair.of(mchApplyment, retOk(null)); + } + + public MutablePair doModifyNotify( + String reviewRelatedId, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, JSONObject bizJSON) { + // 变更 + MchModifyApplymentEntity mchModifyApplyment = modifyApplymentService.getByOrderId(reviewRelatedId, CS.IF_CODE.LKLSPAY); + + if (mchModifyApplyment == null) { + return MutablePair.of(mchApplyment, retOk(null)); + } + + if (!Objects.equals(mchModifyApplyment.getState(), MchApplyment.STATE_WAIT_SIGN) + && !Objects.equals(mchModifyApplyment.getState(), MchApplyment.STATE_AUDITING)) { + // 已经处理过,直接返回 + return MutablePair.of(null, retOk(null)); + } + + handleModifyApply(bizJSON, mchApplyment); + + return MutablePair.of(null, retOk(null)); + } + + private void handleModifyApply(JSONObject bizJSON, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String reviewPass = bizJSON.getString("reviewPass"); + String reviewRelatedId = bizJSON.getString("reviewRelatedId"); + String reviewResult = bizJSON.getString("reviewResult"); + + MchModifyApplyment modifyApplyment = getModifyApplymentByChannelApplyNo(reviewRelatedId); + + IIsvmchModifyApplymentService isvmchModifyApplymentService = IsvFactory.getIsvMchModifyApplymentService(CS.IF_CODE.LKLSPAY); + + if (mchApplyment.getState() == MchApplyment.STATE_SUCCESS) { + // 已经变更完成,直接退出 + return; + } + + + if (reviewPass.equals(LklspayConst.EDIT_PASS)) { + // 变更成功 + handleSuccessfulChange(modifyApplyment, mchApplyment, isvmchModifyApplymentService); + } else { + // 其他状态统一定为驳回 + handleRejectedState(modifyApplyment, reviewResult); + } + } + + private MchModifyApplyment getModifyApplymentByChannelApplyNo(String channelApplyNo) { + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + qWrapper.eq(MchModifyApplymentEntity::getChannelApplyNo, channelApplyNo); + return mchInfoConverter.toModel(modifyApplymentService.getOne(qWrapper)); + } + + private void handleSuccessfulChange(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) { + MutablePair mchModifyPair; + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + mchModifyPair = isvmchModifyApplymentService.localModifyBase(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + mchModifyPair = isvmchModifyApplymentService.localModifySettlement(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_RATE: + mchModifyPair = isvmchModifyApplymentService.localModifyRate(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + mchModifyPair = isvmchModifyApplymentService.localModifySettlementType(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + default: + mchModifyPair = new MutablePair<>(modifyApplyment, mchApplyment); + } + + updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight()); + } + + private void handleRejectedState(MchModifyApplyment modifyApplyment, String note) { + MchModifyApplymentEntity result = new MchModifyApplymentEntity(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + result.setApplyErrorInfo("[" + note + "]"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + modifyApplymentService.updateById(result); + } + + private void updateModificationState(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + MchModifyApplymentEntity dbEntity = mchInfoConverter.toDbEntity(modifyApplyment); + MchApplyment dbEntity1 = mchInfoConverter.toDbEntity(mchApplyment); + + // 状态变更就更新 + if (!modifyApplyment.getState().equals(mchApplyment.getState())) { + modifyApplymentService.updateById(dbEntity); + + // 变更成功就更新商户数据 + if (modifyApplyment.getState() == MchApplyment.STATE_SUCCESS) { + mchApplymentService.updateById(dbEntity1); + } + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..1e56fc0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchModifyApplymentService.java @@ -0,0 +1,366 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.LklspayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.channel.lklspay.util.LklspayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +public class LklspayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + LklspayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, LklspayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + LklspayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, LklspayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setIsLegalInfo("1".equals(mchModifyData.getIllegal()) ? "N" : "Y"); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setLetterOfAuthorizationImg(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair localModifySettlementType(MutablePair mchDataPair) { + String applyDetailInfo = mchDataPair.left.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + mchDataPair.left.setState(MchApplyment.STATE_SUCCESS_INEFFECTIVE); + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put(LklspayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo()); + param.put("merBizName", mchModifyData.getMchShortName()); + // 其他属性暂不考虑 + + try { + JSONObject applyResp = LklspayKit.applymentRequest(LklTkReqMethod.BASE_INFO_CHANGE, isvParams, param); + Long reviewRelatedId = applyResp.getLong(LklspayConst.REVIEW_RELATED_ID); + + resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId)); + resultModifyApplyment.setChannelVar1(applyResp.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String remark = "拉卡拉拓客基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("拉卡拉拓客基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put(LklspayConst.CUSTOMER_NO, mchApplyment.getChannelApplyNo()); + param.put(LklspayConst.ACCOUNT_NAME, mchModifyData.getSettAccountName()); + param.put(LklspayConst.BANK_NAME, mchModifyData.getSettAccountBankName()); + param.put(LklspayConst.BANK_NO, mchModifyData.getBankSubCode()); + param.put(LklspayConst.CLEARING_BANK_NO, mchModifyData.getBankCode()); + param.put(LklspayConst.ACCOUNT_NO, mchModifyData.getSettAccountNo()); + param.put("accountKind", mchModifyData.getSettAccountType().equals("B")? "57": "58"); + + List> attachments = new ArrayList<>(); + param.put("attachments", attachments); + if (mchModifyData.getSettAccountType().equals("B")) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "OPENING_PERMIT"); + Map attachmentItem = new HashMap<>(); + attachmentItem.put("imgPath", imgUploadResult.getString("url")); + attachmentItem.put("imgType", "OPENING_PERMIT"); + attachments.add(attachmentItem); + } + + if (mchModifyData.getSettAccountType().equals("C")) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, mchModifyData.getSettAccountLicenseImg(), "BANK_CARD"); + Map attachmentItem = new HashMap<>(); + attachmentItem.put("imgPath", imgUploadResult.getString("url")); + attachmentItem.put("imgType", "OPENING_PERMIT"); + attachments.add(attachmentItem); + } + + try { + JSONObject applyResp = LklspayKit.applymentRequest(LklTkReqMethod.SETTLE_CHANGE, isvParams, param); + Long reviewRelatedId = applyResp.getLong(LklspayConst.REVIEW_RELATED_ID); + + resultModifyApplyment.setChannelApplyNo(String.valueOf(reviewRelatedId)); + resultModifyApplyment.setChannelVar1(applyResp.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String remark = "拉卡拉基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); +// log.debug("云商服3.0基本信息变更发起成功"); + log.debug("拉卡拉拓客基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + MchModifyApplymentModel modifyApplymentModel = JSON.parseObject(mchDataPair.left.getApplyDetailInfo(), MchModifyApplymentModel.class); + String settlementType = modifyApplymentModel.getSettlementType(); + + LklspayApplymentInfo lklspayApplymentInfo = JSON.parseObject(mchDataPair.right.getApplyDetailInfo(), LklspayApplymentInfo.class); + + JSONObject param = new JSONObject(); + param.put(LklspayConst.CUSTOMER_NO, mchDataPair.right.getChannelApplyNo()); + + List fees = new ArrayList<>(); + Map feesMap = new HashMap(); + lklspayApplymentInfo.getPaywayFeeList().forEach(r -> { + + if (r.getWayCode().startsWith("WX_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "WECHAT"); + fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + } + + if (r.getWayCode().startsWith("ALI_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "ALIPAY"); + fee.put("fee", r.getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + } + + if (r.getWayCode().startsWith("YSF_")) { + JSONObject fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "YSF_DISCOUNT_DEBIT_FEE"); + fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100))); + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "DEBIT_CARD"); + + // 费率模板限制 + fee.put("fee", "0.5d"); + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "YSF_DISCOUNT_CREDIT_FEE"); + fee.put("fee", r.getLevelList().get(0).getFeeRate().multiply(BigDecimal.valueOf(100))); + + feesMap.put(fee.getString("feeType"), fee); + + fee = new JSONObject(); + fees.add(fee); + fee.put("feeType", "CREDIT_CARD"); + fee.put("fee", r.getLevelList().get(1).getFeeRate().multiply(BigDecimal.valueOf(100))); + + feesMap.put(fee.getString("feeType"), fee); + } + }); + + param.put("fees", new ArrayList<>(feesMap.values())); + param.put("settleType", settlementType); + param.put("productCode", LklspayConst.BIZ_CODE_SCAN); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchDataPair.right)); + try { + JSONObject bizData = LklspayKit.applymentRequest(LklTkReqMethod.RATE_CHANGE, isvParams, param); + + String message = bizData.getString("message"); + String reviewRelatedId = bizData.getString("reviewRelatedId"); + + if ("SUCCESS".equals(message)) { + mchDataPair.left.setChannelApplyNo(reviewRelatedId); + // 通过,次日生效,后续操作见定时任务 + mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData)); + mchDataPair.left.setState(MchApplyment.STATE_AUDITING); + + return new MutablePair<>(mchDataPair.left, null); + } else { + // 驳回 + mchDataPair.left.setChannelVar1(processChannelValue(mchDataPair.right.getChannelVar1(), bizData)); + mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchDataPair.left.setApplyErrorInfo("[" + message + "]"); + + return new MutablePair<>(mchDataPair.left, null); + } + } catch (Exception e) { + // 驳回 + mchDataPair.left.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchDataPair.left.setApplyErrorInfo("[" + e.getMessage() + "]"); + + return new MutablePair<>(mchDataPair.left, null); + } + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + MchApplyment mchApplyment = mchDataPair.getRight(); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + param.put(LklspayConst.REVIEW_RELATED_ID, modifyApplyment.getChannelApplyNo()); + + JSONObject bizData = LklspayKit.applymentRequest(LklTkReqMethod.CHANGE_STATUS_GET, isvParams, param); + String reviewPass = bizData.getString("reviewPass"); + String reviewResult = bizData.getString("reviewResult"); + if (!ObjectUtils.isEmpty(reviewResult)) { + resultModifyApplyment.setApplyErrorInfo("[" + reviewResult + "]"); + } + + if ("PASS".equals(reviewPass)) { + // 通过 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + return handleSuccessCase(modifyApplyment, mchDataPair); + } + + if ("UNPASS".equals(reviewPass)) { + // 驳回 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + bizData.getString("note") + "]"); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return mchDataPair; + } + + private MutablePair handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair mchDataPair) { + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT_TYPE: + return localModifySettlementType(mchDataPair); + default: + return mchDataPair; + } + } + + private String processChannelValue(String channelVal, JSONObject bizData) { + JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal); + channelValJSON.putAll(bizData); + return channelValJSON.toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchWxConfigService.java new file mode 100644 index 0000000..ef77863 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayIsvmchWxConfigService.java @@ -0,0 +1,142 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class LklspayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + LklspayIsvParams isvParams = (LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = LklspayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("WXZF")) + .collect(Collectors.toList()); + + if (CollUtil.isNotEmpty(filteredMercList)) { + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + result.setChannelSubMchId(subMchId); + } + + uWrapper.eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, "WX"); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxOpenUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (result.getChannelSubMchId() != null) { + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "WECHAT") + .fluentPut("subMerchantId", result.getChannelSubMchId()); + + JSONObject respData = LklspayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState) + || "UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + result.setState("未授权"); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + result.setState("已授权"); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()); + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + + mchSubInfoService.update(null, uWrapper); + } + + + return result; + } + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayKit.java new file mode 100644 index 0000000..b0d89dd --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayKit.java @@ -0,0 +1,628 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.com.sand.hmpay.util.StringUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.PemUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.http.ContentType; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.*; +import com.jeequan.jeepay.thirdparty.channel.lklspay.util.LklspayConst; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AccessLevel; +import lombok.Cleanup; +import lombok.NoArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.HttpStatusCodeException; + +import javax.xml.bind.DatatypeConverter; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.PRECONDITION_FAILED; + +/** + * TODO + * + * @author crystal + * @date 2023/11/22 15:49 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LklspayKit { + + public static final Logger log = LoggerFactory.getLogger(LklspayKit.class); + + public static final String RESP_APPID_HEADER = "Lklapi-Appid"; + + public static final String RESP_SERIAL_HEADER = "Lklapi-Serial"; + + public static final String RESP_TIMESTAMP_HEADER = "Lklapi-Timestamp"; + + public static final String RESP_NONCE_HEADER = "Lklapi-Nonce"; + + public static final String RESP_SIGNATURE_HEADER = "Lklapi-Signature"; + + public static final String SCHEMA = "LKLAPI-SHA256withRSA"; + + public static final String SUCCESS_CODE = "000000"; + + public static final String EXT_SUCCESS_CODE = "BBS00000"; + + public static final String PAYING_SUCCESS_CODE = "BBS10000"; + + private static JSONObject token; + + private static JSONObject editToken; + + public static JSONObject uploadRequest(LklspayIsvParams isvParams, String fileUrl, String imgType) { + reqAuditToken(isvParams); + + log.info("拉卡拉上传图片, 上传图片类型为{}, 上传图片链接为{}", imgType, fileUrl); + HttpRequest httpRequest = HttpRequest.post(LklTkReqMethod.UPLOAD.getUrl()) + .contentType(ContentType.MULTIPART.name()) + .header("Authorization", "bearer " + token.getString("access_token")); + + byte[] byteArray = HttpUtil.downloadBytes(fileUrl); + Image read = ImgUtil.toImage(byteArray); + + while (byteArray.length > 1024 * 1024) { + read = ImgUtil.scale(read, 0.9f); + byteArray = ImgUtil.toBytes(read, "jpg"); + } +// ByteArrayResource file = new ByteArrayResource(byteArray) { +// @Override +// public String getFilename() { +// return "test.jpg"; +// } +// }; + + httpRequest.form("file", byteArray, "test.jpg"); + httpRequest.form("imgType", imgType); + httpRequest.form("sourcechnl", "0"); + httpRequest.form("isOcr", false); + + HttpResponse execute = null; + try { + execute = httpRequest.execute(); + if (execute.isOk()) { + return JSON.parseObject(execute.body()); + } else { + log.info("拉卡拉上传图片异常, 上传图片类型为{}, 上传图片链接为{}", imgType, fileUrl); + throw new BizException("拉卡拉上传图片异常"); + } + + } catch (HttpStatusCodeException e) { + token = null; + throw e; + } finally { + if (execute != null) { + execute.close(); + } + } + } + + public static JSONObject uploadRequest(LklspayIsvParams isvParams, File file, String imgType) { + reqAuditToken(isvParams); + + HttpRequest httpRequest = HttpRequest.post(LklTkReqMethod.UPLOAD.getUrl()) + .contentType(ContentType.MULTIPART.name()) + .header("Authorization", "bearer " + token.getString("access_token")); + + httpRequest.form("file", file); + httpRequest.form("imgType", imgType); + httpRequest.form("sourcechnl", "0"); + httpRequest.form("isOcr", false); + + HttpResponse execute = null; + try { + execute = httpRequest.execute(); + if (execute.isOk()) { + return JSON.parseObject(execute.body()); + } else { + log.info("拉卡拉上传图片异常, 上传图片类型为{}", imgType); + throw new BizException("拉卡拉上传图片异常"); + } + + } catch (HttpStatusCodeException e) { + token = null; + throw e; + } finally { + if (execute != null) { + execute.close(); + } + } + } + + private static void reqAuditToken(LklspayIsvParams isvParams) { + token = getToken(isvParams); + } + + /** + * 获取入网token + * + * @return + */ + private static JSONObject getToken(LklspayIsvParams isvParams) { + String clientInfo = isvParams.getClientId() + ":" + isvParams.getClientSecret(); + String encodeClientInfo = Base64.encode(clientInfo); + + try { + @Cleanup HttpResponse execute = HttpRequest.post(LklTkReqMethod.TOKEN_AUDIT.getUrl()) + .header("Authorization", "Basic " + encodeClientInfo) + .form("grant_type", "client_credentials") + .form("client_id", isvParams.getClientId()) + .form("client_secret", isvParams.getClientSecret()) + .execute(); + log.info("请求结果: {}", execute.body()); + JSONObject token = JSON.parseObject(execute.body()); + if (!execute.isOk()) { + throw new BizException(execute.body()); + } + token.put("expire_in", token.getIntValue("expire_in") + System.currentTimeMillis() / 1000L); + return token; + } catch (Exception e) { + log.info("token获取失败", e); + throw new BizException("token获取失败"); + } + } + + private static void reqAuditEditToken(LklspayIsvParams isvParams) { + editToken = getEditToken(isvParams); + } + + private static JSONObject getEditToken(LklspayIsvParams isvParams) { + String clientInfo = isvParams.getClientId() + ":" + isvParams.getClientSecret(); + String encodeClientInfo = Base64.encode(clientInfo); + + try { + @Cleanup HttpResponse execute = HttpRequest.post(LklTkReqMethod.TOKEN_EDIT.getUrl()) + .header("Authorization", "Basic " + encodeClientInfo) + .form("grant_type", "password") + .form("username", isvParams.getAppUserName()) + .form("password", isvParams.getAppPassword()) + .form("scope", "all") + .execute(); + log.info("请求结果: {}", execute.body()); + JSONObject token = JSON.parseObject(execute.body()); + if (!execute.isOk()) { + throw new BizException(execute.body()); + } + token.put("expire_in", token.getIntValue("expire_in") + System.currentTimeMillis() / 1000L); + return token; + } catch (Exception e) { + log.info("token获取失败", e); + throw new BizException("token获取失败"); + } + } + + public static JSONObject applymentRequest(ILklTkReqMethod reqMethod, LklspayIsvParams isvParams, JSONObject param) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉配置信息"); + + log.info("LklspayIsvParams:{}", JSONUtil.toJsonStr(isvParams)); + + if (reqMethod.getUrlFlag().equals(LklspayConst.AUDIT)) { + reqAuditToken(isvParams); + } else { + reqAuditEditToken(isvParams); + } + + String url = reqMethod.getUrl(); + String templateWord = reqMethod.getTemplateWord(); + if (!ObjectUtils.isEmpty(templateWord)) { + String paramWord = param.getString(templateWord.replaceAll("[{}]", "")); + url = url.replace(templateWord, paramWord); + } + + log.info("拉卡拉请求链接: {}", url); + log.info("拉卡拉请求参数: {}", param); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(reqMethod.getContentType()); + if (reqMethod.getUrlFlag().equals(LklspayConst.AUDIT)) { + headers.add("Authorization", "bearer " + token.getString("access_token")); + } else { + headers.add("Authorization", "bearer " + editToken.getString("access_token")); + } + log.info("拉卡拉请求头:{}", JSON.toJSONString(headers)); + + if (reqMethod.getContentType().equals(MediaType.APPLICATION_FORM_URLENCODED)) { + + HttpResponse execute = null; + if (reqMethod.getMethod().equals(LklpayConst.POST)) { + try { + HttpRequest httpRequest = HttpRequest.post(url); + if (reqMethod.getUrlFlag().equals(LklspayConst.AUDIT)) { + httpRequest.header("Authorization", "bearer " + token.getString("access_token")); + } else { + httpRequest.header("Authorization", "bearer " + editToken.getString("access_token")); + } + + for (Map.Entry entry : param.entrySet()) { + httpRequest.form(entry.getKey(), entry.getValue()); + } + + execute = httpRequest.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + throw new BizException(body); + } + + } catch (HttpStatusCodeException e) { + token = null; + handleHttpStatusCodeException(e); + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + throw new BizException("拉卡拉请求异常"); + } finally { + if (execute != null) { + execute.close(); + } + } + } + + if (reqMethod.getMethod().equals(LklspayConst.GET)) { + try { + url += "?"; + + HttpRequest httpRequest = HttpRequest.get(url); + + if (reqMethod.getUrlFlag().equals(LklspayConst.AUDIT)) { + httpRequest.header("Authorization", "bearer " + token.getString("access_token")); + } else { + httpRequest.header("Authorization", "bearer " + editToken.getString("access_token")); + } + + for (Map.Entry entry : param.entrySet()) { + httpRequest.form(entry.getKey(), entry.getValue()); + } + execute = httpRequest.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + throw new BizException(body); + } + } catch (HttpStatusCodeException e) { + token = null; + handleHttpStatusCodeException(e); + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + throw new BizException("拉卡拉请求异常"); + } finally { + if (execute != null) { + execute.close(); + } + } + } + } + + if (MediaType.APPLICATION_JSON.equals(reqMethod.getContentType())) { + RSA rsa = null; + HttpRequest post = HttpRequest.post(url).header(headers); + if (reqMethod.isEncrypt()) { + rsa = SecureUtil.rsa(LklTkReqMethod.PRI_KEY, LklTkReqMethod.PUB_KEY); + String encryptBase64 = rsa.encryptBase64(param.toJSONString(), KeyType.PrivateKey); + JSONObject reqParam = new JSONObject(); + reqParam.put("data", encryptBase64); + post.body(reqParam.toJSONString()); + } else { + post.body(param.toJSONString()); + } + + try { + @Cleanup HttpResponse execute = post.execute(); + String body = execute.body(); + if (execute.isOk()) { + log.info("拉卡拉请求返回结果:{}", body); + + JSONObject respData = JSON.parseObject(body); + String encryptData = respData.getString("data"); + if (reqMethod.isEncrypt()) { + String encryptRespData = rsa.decryptStr(encryptData, KeyType.PublicKey); + log.info("拉卡拉请求返回结果解密:{}", encryptRespData); + + return JSON.parseObject(encryptRespData); + } + + return JSON.parseObject(body); + } else { + log.info("拉卡拉请求返回结果:{}", body); + + if (execute.getStatus() == 400 || execute.getStatus() == 412 || execute.getStatus() == 500) { + throw new BizException(JSON.parseObject(body).getString("message")); + } + + throw new BizException(body); + } + + } catch (Exception e) { + log.info("拉卡拉请求异常", e); + if (e instanceof BizException) { + throw e; + } + throw new BizException("拉卡拉请求异常, " + e.getMessage()); + } + } + + throw new BizException("拉卡拉请求异常"); + } + + public static JSONObject openRequest(ILklTkReqMethod method, LklspayIsvParams isvParams, JSONObject params) { + JSONObject reqParam = new JSONObject(); + reqParam.put("ver", "v1.0.0"); + reqParam.put("timestamp", String.valueOf(System.currentTimeMillis())); + reqParam.put("rnd", UUID.randomUUID().toString().replace("-", "")); + reqParam.put("reqId", UUID.randomUUID().toString().replace("-", "")); + reqParam.put("reqData", params); + + Map headers = getAuthorization(isvParams, reqParam.toString()); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqParam.toString()).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + checkSign(isvParams, response); + return JSON.parseObject(response.body()).getJSONObject("respData"); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + return new JSONObject(); + } + } + + public static Map getAuthorization(LklspayIsvParams isvParams, String body) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉入网配置信息"); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPrivateCert()); + InputStream inputStream = FileUtil.getInputStream(certFilePath); + String nonceStr = RandomUtil.randomString(16); + Map headers = new HashMap<>(1); + long timestamp = System.currentTimeMillis() / 1000; + String data = isvParams.getAppId() + "\n" + isvParams.getSerialNo() + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"; + byte[] privateKey = PemUtil.readPem(inputStream); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKey, null); + sign.sign(data); + String signature = Base64.encode(sign.sign(data)); + try { + String authorization = "appid=\"" + isvParams.getAppId() + "\"," + "serial_no=\"" + isvParams.getSerialNo() + "\"," + "timestamp=\"" + + timestamp + "\"," + "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\""; + headers.put("Authorization", SCHEMA + " " + authorization); + log.info("【拉卡拉】接口请求参数:{}",body); + return headers; + } catch (Exception e) { + throw new BizException("拉卡拉接口授权参数异常"); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static boolean checkSign(LklspayIsvParams isvParams, HttpResponse response) { + String respAppid = response.header(RESP_APPID_HEADER); + String respSerial = response.header(RESP_SERIAL_HEADER); + String respTimestamp = response.header(RESP_TIMESTAMP_HEADER); + String respNonce = response.header(RESP_NONCE_HEADER); + String repsSignature = response.header(RESP_SIGNATURE_HEADER); + String source = respAppid + "\n" + respSerial + "\n" + respTimestamp + "\n" + respNonce + "\n" + response.body() + "\n"; + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + Assert.notNull(configContextQueryService, "无法获取拉卡拉入网配置信息"); + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicCert()); + InputStream inputStream = FileUtil.getInputStream(certFilePath); + try { + Certificate certificate = SecureUtil.readX509Certificate(inputStream); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA).setCertificate(certificate); + return sign.verify(source.getBytes(StandardCharsets.UTF_8), DatatypeConverter.parseBase64Binary(repsSignature)); + } catch (Exception e) { + return false; + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 设置通道参数 + * + * @param mchAppConfigContext + * @param bizContent + */ + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String ip) { + LklspayIsvsubMchParams mchParams = JSON.parseObject(mchAppConfigContext.getMchApplyment().getSuccResParameter(), LklspayIsvsubMchParams.class); + bizContent.put("merchant_no", mchParams.getExternalCustomerNo()); + bizContent.put("term_no", mchParams.getTermNo()); + if (StringUtil.isNotEmpty(ip)) { + JSONObject location_info = new JSONObject(1); + location_info.put("request_ip", ip); + bizContent.put("location_info", location_info); + } + } + + /** + * 请求 + * + * @return + */ + public static JSONObject payRequest(LklPayMethod.Api method, MchApplyment mchApplyment, JSONObject params) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + JSONObject reqParam = new JSONObject(); + reqParam.put("version", "3.0"); + reqParam.put("req_time", DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_FORMAT)); + reqParam.put("req_data", params); + Map headers = getAuthorization(isvParams, reqParam.toString()); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqParam.toString()).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + JSONObject responseBody = JSON.parseObject(response.body()); + if(!EXT_SUCCESS_CODE.equals(responseBody.getString("code")) && !PAYING_SUCCESS_CODE.equals(responseBody.getString("code"))){ + throw new BizException(responseBody.getString("msg")); + } + checkSign(isvParams, response); + return responseBody.getJSONObject("resp_data"); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + return new JSONObject(); + } + } + + public static void handleHttpClientErrorException(HttpStatusCodeException e) { + log.info("http code exception", e); + byte[] responseBodyAsByteArray = e.getResponseBodyAsByteArray(); + String resp = new String(responseBodyAsByteArray, StandardCharsets.UTF_8); + log.info("拉卡拉请求返回结果:{}", resp); + JSONObject error = JSON.parseObject(resp); + String errorMsg; + String msg; + HttpStatus statusCode = e.getStatusCode(); + if (statusCode.equals(BAD_REQUEST) || statusCode.equals(PRECONDITION_FAILED)) { + errorMsg = error.getString("message"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(msg); + } else { + errorMsg = StringUtil.isNotEmpty(error.getString("retMsg")) ? error.getString("retMsg") : error.getString("msg"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(msg); + } + } + + public static void handleHttpStatusCodeException(HttpStatusCodeException e) { + log.info("拉卡拉请求异常返回码", e); + byte[] responseBodyAsByteArray = e.getResponseBodyAsByteArray(); + String resp = new String(responseBodyAsByteArray, StandardCharsets.UTF_8); + log.info("拉卡拉请求返回结果:{}", resp); + + JSONObject error = JSON.parseObject(resp); + String errorMsg; + String msg; + switch (e.getStatusCode()) { + case BAD_REQUEST: + case PRECONDITION_FAILED: + // 汇拓客的接口 + errorMsg = error.getString("message"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + throw new BizException(errorMsg); + default: + errorMsg = StringUtil.isNotEmpty(error.getString("retMsg")) ? error.getString("retMsg") : error.getString("msg"); + msg = String.format("接口请求异常,请求code:%s, 异常信息:%s", e.getStatusCode(), errorMsg); + break; + } + + throw e; + } + + public static JSONObject ok() { + JSONObject result = new JSONObject(2); + result.put("code", "SUCCESS"); + result.put("message", "处理成功"); + return result; + } + + /** + * 商户相关参数请求 + * + * @param method + * @param bizContent + * @return + */ + public static JSONObject reqMch(LklPayMethod.Api method, LklspayIsvParams isvParams, JSONObject bizContent) { + if (method == LklPayMethod.Api.WECHAT_PARAMS_CONFIG_URL) { + bizContent.put("channlId", isvParams.getWxChannelId()); + } + LklMchReq req = new LklMchReq(bizContent); + return reqApi(method, isvParams, JSON.toJSONString(req)); + } + + public static JSONObject reqApi(LklPayMethod.Api method, LklspayIsvParams isvParams, String reqBody) { + log.info("【拉卡拉】接口请求地址:{}",method.getUrl()); + Map headers = getAuthorization(isvParams, reqBody); + try { + HttpResponse response = HttpRequest.post(method.getUrl()).addHeaders(headers).body(reqBody).execute(); + log.info("拉卡拉返回参数:{}", response.body()); + return initResult(isvParams, response); + } catch (HttpStatusCodeException e) { + handleHttpClientErrorException(e); + throw new BizException("接口异常"); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 发起结算信息请求 + * + * @param method + * @param bizData + * @param isvParams + * @return + */ + public static JSONObject reqSettle(LklPayMethod.Api method, JSONObject bizData, LklspayIsvParams isvParams) { + LklSettleReq reqData = new LklSettleReq(bizData); + return reqApi(method, isvParams, JSON.toJSONString(reqData)); + } + + private static JSONObject initResult(LklspayIsvParams isvParams, HttpResponse response) { + boolean verify = checkSign(isvParams, response); + if (!verify) { + throw new BizException("签名校验异常"); + } + JSONObject responseBody = JSON.parseObject(response.body()); + String retCode = responseBody.getString("retCode"); + if (!SUCCESS_CODE.equals(retCode)) { + throw new BizException(responseBody.getString("retMsg")); + } + Object respData = responseBody.get("respData"); + if(respData instanceof JSONObject){ + return (JSONObject) respData; + } + return responseBody; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApiService.java new file mode 100644 index 0000000..80e2043 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApiService.java @@ -0,0 +1,571 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.applyment.LklspayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +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 com.jeequan.jeepay.db.entity.BankBranchLkl; +import com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.service.mapper.BankBranchLklMapper; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklMercInfoConn; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; + +/** + * TODO + * + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class LklspayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private Configuration configuration; + + @Autowired + private BankBranchLklMapper bankBranchLklMapper; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + private String getEndDate(String endDate) { + if ("长期".equals(endDate)) { + return "2099-12-31"; + } + + return endDate; + } + + private LklMercInfoConn getLklData(LklspayApplymentInfo applymentInfo, LklspayIsvParams isvParams) { + LklMercInfoConn mercInfo = new LklMercInfoConn(); + mercInfo.setUserNo(Long.parseLong(isvParams.getUserNo())); + mercInfo.setEmail("18062761507@163.com"); + mercInfo.setBusiCode(LklpayConst.BIZ_CODE_SCAN); + + if (com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_PERSONAL == applymentInfo.getMerchantType()) { + mercInfo.setMerType("TP_PERSONAL"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } else { + mercInfo.setMerType("TP_MERCHANT"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } + + mercInfo.setMerName(applymentInfo.getMchShortName()); + mercInfo.setMerAddr(applymentInfo.getAddress()); + + mercInfo.setProvinceCode(applymentInfo.getMchAreaCode().getString(0)); + mercInfo.setCityCode(applymentInfo.getMchAreaCode().getString(1)); + mercInfo.setCountyCode(applymentInfo.getMchAreaCode().getString(2)); + + if (1 != applymentInfo.getMerchantType()) { + // 非小微商户提交营业执照信息 + mercInfo.setLicenseName(applymentInfo.getMchFullName()); + mercInfo.setLicenseNo(applymentInfo.getLicenseNo()); + mercInfo.setLicenseDtStart(applymentInfo.getLicenseEffectBegin()); + mercInfo.setLicenseDtEnd(getEndDate(applymentInfo.getLicenseEffectEnd())); + } + // 接口的经纬度字段是反的 + mercInfo.setLatitude(applymentInfo.getLatitude()); + mercInfo.setLongtude(applymentInfo.getLongtude()); + mercInfo.setSource("APP"); + + Assert.notNull(applymentInfo.getMccCode(), "缺少mcc编码信息"); + String[] mccInfo = applymentInfo.getMccCode().split("_"); + if (mccInfo.length != 2) { + throw new BizException("mcc数据异常"); + } + mercInfo.setBusinessContent(mccInfo[0]); + mercInfo.setLarName(applymentInfo.getIdcardName()); + mercInfo.setLarIdType("01"); + mercInfo.setLarIdCard(applymentInfo.getIdcardNo()); + mercInfo.setLarIdCardStart(applymentInfo.getIdcardEffectBegin()); + mercInfo.setLarIdCardEnd(getEndDate(applymentInfo.getIdcardEffectEnd())); + mercInfo.setContactMobile(applymentInfo.getContactPhone()); + mercInfo.setContactName(applymentInfo.getContactName()); + + BankBranchLkl bankCodeLkl = bankBranchLklMapper.selectByContactLine(applymentInfo.getOpenningBankCode()); + Assert.notNull(bankCodeLkl, "未获取到支行信息,请重新选择支行信息"); + + mercInfo.setOpenningBankCode(bankCodeLkl.getContactLine()); + mercInfo.setOpenningBankName(bankCodeLkl.getBranchName()); + mercInfo.setClearingBankCode(bankCodeLkl.getClearNo()); + + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaCode(), "缺少支行地区编码信息"); + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaName(), "缺少支行地区信息"); + mercInfo.setSettleProvinceCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(0)); + mercInfo.setSettleProvinceName(applymentInfo.getSettAccountBankBranchAreaName().getString(0)); + mercInfo.setSettleCityCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(1)); + mercInfo.setSettleCityName(applymentInfo.getSettAccountBankBranchAreaName().getString(1)); + mercInfo.setAccountNo(applymentInfo.getSettAccountNo()); + mercInfo.setAccountName(applymentInfo.getSettAccountName()); + mercInfo.setAccountType(applymentInfo.getSettAccType()); + mercInfo.setAccountIdType("01"); + mercInfo.setAccountIdCard(applymentInfo.getSettAccountIdcardNo()); + mercInfo.setAccountIdDtStart(applymentInfo.getSettAccountIdcardEffectBegin()); + mercInfo.setAccountIdDtEnd(getEndDate(applymentInfo.getSettAccountIdcardEffectEnd())); + + mercInfo.setBizContent(getFeeInfo(applymentInfo, isvParams)); + mercInfo.setSettleType(applymentInfo.getSettleType()); + mercInfo.setSettlementType("AUTOMATIC"); + + return mercInfo; + } + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + private LklMercInfoConn.BizContent getFeeInfo(LklspayApplymentInfo applymentInfo, LklspayIsvParams isvParams) { + Map map = new HashMap<>(); + + List paywayFeeList = applymentInfo.getPaywayFeeList(); + + for (PaywayFee paywayFee : paywayFeeList) { + boolean isYsfLevelFee = (paywayFee.getWayCode().startsWith("YSF_") || paywayFee.getWayCode().startsWith("UP_")) + && PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) + && CollUtil.isNotEmpty(paywayFee.getLevelList()); + if (isYsfLevelFee) { + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + map.put("YSF_DISCOUNT_DEBIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee1)); + + PaywayFee paywayFee2DebitCard = paywayFee.getLevelList().get(1); + double topFee2 = (double) paywayFee2DebitCard.getMaxFee() / 100L; + map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", 0.5d, topFee2)); +// map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee2)); + } + + PaywayFee creditCardPaywayFee = paywayFee.getCreditCardPaywayFee(); + if (creditCardPaywayFee != null && CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()) && (CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()))) { + PaywayFee paywayFeeCrebitCard = creditCardPaywayFee.getLevelList().get(0); + map.put("YSF_DISCOUNT_CREDIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFeeCrebitCard.getFeeRate())), null)); + + PaywayFee paywayFee2CrebitCard = creditCardPaywayFee.getLevelList().get(1); + map.put("CREDIT_CARD", new LklMercInfoConn.Fee("CREDIT_CARD", Double.parseDouble(convertRate(paywayFee2CrebitCard.getFeeRate())), null)); + + } + + if (paywayFee.getWayCode().startsWith("WX_")) { + map.put("WECHAT", new LklMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + + if (paywayFee.getWayCode().startsWith("ALI_")) { + map.put("ALIPAY", new LklMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + if (CS.PAY_WAY_CODE.D0.equals(paywayFee.getWayCode())) { + // D0费率 + double d0Rate = Double.parseDouble(convertRate(paywayFee.getFeeRate())); + // 扫码d0费率 + map.put("SCAN_PAY_SECOND", new LklMercInfoConn.Fee("SCAN_PAY_SECOND", d0Rate, null)); + // 刷卡D0费率 + map.put("CARD_SECOND", new LklMercInfoConn.Fee("CARD_SECOND", d0Rate, null)); + } + + if (CS.PAY_WAY_CODE.SCAN.equals(paywayFee.getWayCode())) { + // 线上费率 + map.put("WECHAT", new LklMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + map.put("ALIPAY", new LklMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + // 银联借记卡,云闪付优惠费率,1000以下的交易费率 + map.put("YSF_DISCOUNT_DEBIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFee.getFeeRate())), topFee1)); + + // 银联费率有银联费率模版限制,写死,一般不用作实际交易 + map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", 0.5d, 20d)); + // 银联贷记卡,云闪付优惠费率,1000以下的交易费率 + map.put("YSF_DISCOUNT_CREDIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + map.put("CREDIT_CARD", new LklMercInfoConn.Fee("CREDIT_CARD", 0.6d, null)); + } + } + + LklMercInfoConn.BizContent bizContent = new LklMercInfoConn.BizContent(); + + String[] mccInfo = applymentInfo.getMccCode().split("_"); + bizContent.setMcc(mccInfo[1]); + // 25为B2B收银台 13位专业扫码 + bizContent.setActivityId(LklpayConst.ACTIVITY_ID_WECHAT_PAY); + bizContent.setTermNum("1"); + bizContent.setFees(new HashSet<>(map.values())); + + return bizContent; + } + + private File writeHtml(Template template, LklspayApplymentInfo lklspayApplymentInfo, LklspayIsvParams isvParams) throws IOException, TemplateException { + Map param = new HashMap<>(); + Map fee = new HashMap<>(); + + LklMercInfoConn lklData = getLklData(lklspayApplymentInfo, isvParams); + fee.put("customerName", Optional.ofNullable(lklData.getContactName()).orElse("")); + param.put("fee", fee); + param.put("licenseNo", Optional.ofNullable(lklData.getLicenseNo()).orElse("")); + param.put("legalName", Optional.ofNullable(lklData.getLarName()).orElse("")); + param.put("licenseName", Optional.ofNullable(lklData.getLicenseName()).orElse("")); + param.put("identityNo", Optional.ofNullable(lklData.getLarIdCard()).orElse("")); + param.put("address", lklData.getMerAddr()); + param.put("receiveDetail", Optional.ofNullable(lklData.getMerAddr()).orElse("")); + param.put("identityNoExpire", Optional.ofNullable(getEndDate(lklData.getLicenseDtEnd())).orElse("")); + param.put("accountName", Optional.ofNullable(lklData.getAccountName()).orElse("")); + param.put("accountIdCard", Optional.ofNullable(lklData.getAccountIdCard()).orElse("")); + param.put("accountNo", Optional.ofNullable(lklData.getAccountNo()).orElse("")); + param.put("accountIdDtEnd", Optional.ofNullable(getEndDate(lklData.getAccountIdDtEnd())).orElse("")); + param.put("bankName", Optional.ofNullable(lklData.getOpenningBankName()).orElse("")); + param.put("mail", Optional.ofNullable(lklData.getEmail()).orElse("")); + param.put("contactManName", Optional.ofNullable(lklData.getContactName()).orElse("")); + param.put("channelType", Optional.ofNullable(lklData.getMerType()).orElse("")); + param.put("phone", Optional.ofNullable(lklData.getContactMobile()).orElse("")); + param.put("agencyName", "拉卡拉"); + param.put("width", "600px"); + param.put("tbTitleWidth", "60px"); + param.put("tbConWidth", "60px"); + + String fileName = UUID.randomUUID().toString(); + File htmlFile = new File(FileUtil.getTmpDir(), fileName + ".html"); + FileWriter sw = new FileWriter(htmlFile); + log.info("生成协议html, 地址:{}, 参数:{} ", htmlFile.getAbsolutePath(), param); + template.process(param, sw); + + return htmlFile; + } + + private static File createAgreementPicture(File htmlFile) throws IOException { + File outputFile = new File(FileUtil.getTmpDir(), htmlFile.getName() + ".jpg"); + log.info("生成图片开始, HTML地址 {}, 图片地址:{}", htmlFile.getAbsolutePath(), outputFile.getAbsolutePath()); + /** + * 生成图片说明,需要在服务器上安装需要的字体,等线字体即可,可在windows系统字体库中获得 + * 将字体放在服务器/usr/share/fonts/myfonts目录中, + * 运行 sudo fc-cache -f -v 命令 即可刷新字体缓存 + */ + String commandProcess = "wkhtmltoimage --width 400 --quality 94 " + htmlFile.getPath() + " " + outputFile.getPath(); + log.info("协议执行Process command:{}", commandProcess); + long startTime = System.currentTimeMillis(); //获取开始时间 + Process process = Runtime.getRuntime().exec(commandProcess); + try { + int exitVal = process.waitFor(); + log.info("协议html转换png结果:{}", exitVal); + } catch (InterruptedException e) { + log.info("协议html转换png错误", e); + Thread.currentThread().interrupt(); + throw new IOException(e); + } + long endTime = System.currentTimeMillis(); //获取结束时间 + log.info("程序运行时间: " + (endTime - startTime) + "ms"); + log.info("生成图片结束,地址: {}", outputFile.getPath()); + Thumbnails.of(outputFile).scale(1).outputQuality(0.9).toFile(outputFile); + return outputFile; + } + + public MchApplyment submitMchInfo(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + + String channelVar1 = mchApplyment.getChannelVar1(); + Type type = new TypeReference>() { + }.getType(); + Set attachments = JSON.parseObject(channelVar1, type); + + LklspayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), LklspayApplymentInfo.class); + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode())); + + LklMercInfoConn lklData = getLklData(applymentInfo, isvParams); + + lklData.setAttchments(attachments); + + JSONObject resp = LklspayKit.applymentRequest(LklTkReqMethod.AUDIT, isvParams, (JSONObject) JSON.toJSON(lklData)); + String status = resp.getString("status"); + String customerNo = resp.getString("merchantNo"); + if (status.equals("WAIT_AUDI")) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING); + result.setChannelApplyNo(customerNo); + } + + // 进件响应参数 + result.setSettlementType(applymentInfo.getSettleType()); + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING); + + return result; + } + + public MchApplyment uploadImg(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + + File agreementPicture; + + LklspayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), LklspayApplymentInfo.class); + Assert.notNull(applymentInfo.getAreaName(), "经营地区名称[areaName]不能为空"); + Assert.isFalse(applymentInfo.getAreaName().isEmpty(), "经营地区名称[areaName]不能为空"); + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode())); + + try { + Template template = configuration.getTemplate("lkltkpay/indexHTKWECHAT_PAY.html.ftl"); + File file = writeHtml(template, applymentInfo, isvParams); + agreementPicture = createAgreementPicture(file); + } catch (Exception e) { + log.info("创建拉卡拉汇拓客协议图片失败", e); + throw new BizException("创建拉卡拉汇拓客协议图片失败, " + e.getMessage()); + } + + Set attachments = new HashSet<>(); + uploadRequest(attachments, "AGREE_MENT", agreementPicture, isvParams); + uploadRequest(attachments, "SHOP_OUTSIDE_IMG", applymentInfo.getStoreOuterImg(), isvParams); + uploadRequest(attachments, "SHOP_INSIDE_IMG", applymentInfo.getStoreInnerImg(), isvParams); + uploadRequest(attachments, "CHECKSTAND_IMG", applymentInfo.getStoreCashierImg(), isvParams); + uploadRequest(attachments, "ID_CARD_FRONT", applymentInfo.getIdcard1Img(), isvParams); + uploadRequest(attachments, "ID_CARD_BEHIND", applymentInfo.getIdcard2Img(), isvParams); + + if (applymentInfo.getMerchantType() != com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_PERSONAL) { + uploadRequest(attachments, "BUSINESS_LICENCE", applymentInfo.getLicenseImg(), isvParams); + + if (com.jeequan.jeepay.core.entity.MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(applymentInfo.getSettAccountType())) { + uploadRequest(attachments, "BANK_CARD", applymentInfo.getSettAccountLicenseImg(), isvParams); + } + + if (com.jeequan.jeepay.core.entity.MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(applymentInfo.getSettAccountType())) { + uploadRequest(attachments, "OPENING_PERMIT", applymentInfo.getCompanyAccountLicenseImg(), isvParams); + } + } + + if (!"1".equals(applymentInfo.getIsLegalInfo())) { + uploadRequest(attachments, "SETTLE_ID_CARD_FRONT", applymentInfo.getSettAccountIdcard1Img(), isvParams); + uploadRequest(attachments, "SETTLE_ID_CARD_BEHIND", applymentInfo.getSettAccountIdcard2Img(), isvParams); + uploadRequest(attachments, "LETTER_OF_AUTHORIZATION", applymentInfo.getLetterOfAuthorizationImg(), isvParams); + } else { + uploadRequest(attachments, "SETTLE_ID_CARD_FRONT", applymentInfo.getIdcard1Img(), isvParams); + uploadRequest(attachments, "SETTLE_ID_CARD_BEHIND", applymentInfo.getIdcard2Img(), isvParams); + } + + result.setState(MchApplyment.STATE_AUDITING_WAIT); + result.setRemainStep((byte) 1); + + result.setChannelVar1(JSON.toJSONString(attachments)); + + return result; + } + + public void uploadRequest(Set attachmentList, String key, File file, LklspayIsvParams isvParams) { + attachmentList.add(getAttachment(isvParams, file, key)); + } + + public void uploadRequest(Set attachmentList, String key, String imgUrl, LklspayIsvParams isvParams) { + // 下载文件 + LklMercInfoConn.Attachment attach = getAttachment(isvParams, imgUrl, key); + attachmentList.add(attach); + } + + private static LklMercInfoConn.Attachment getAttachment(LklspayIsvParams isvParams, File file, String imgType) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, file, imgType); + LklMercInfoConn.Attachment attachmentItem = new LklMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private static LklMercInfoConn.Attachment getAttachment(LklspayIsvParams isvParams, String fileUrl, String imgType) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, fileUrl, imgType); + LklMercInfoConn.Attachment attachmentItem = new LklMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * mchRq + * + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + preWxParamsCheck(mchRq); + JSONObject bizData = new JSONObject(); + bizData.put("merCupNo", applyment.getChannelMchNo()); + if (ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())) { + bizData.put("confType", "JSAPI_PATH"); + bizData.put("jsapiPath", mchRq.getJsapiPath()); + } else { + bizData.put("subAppid", mchRq.getAppid()); + bizData.put("confType", "SUB_APPID"); + } + bizData.put("subMchId", mchRq.getSubMchNo()); + LklspayIsvParams isvParams = (LklspayIsvParams) configContextQueryService.queryIsvParams(applyment); + JSONObject result = LklspayKit.reqMch(LklPayMethod.Api.WECHAT_PARAMS_CONFIG_URL, isvParams, bizData); + return ChannelRetMsg.confirmSuccess(null); + } + + /** + * 校验拉卡拉微信参数配置 + * + * @param mchRq + */ + private void preWxParamsCheck(ChannelMchRq mchRq) { + if (StringUtils.isEmpty(mchRq.getSubMchNo())) { + throw new BizException("调用拉卡拉配置微信参数接口失败,缺失微信子商户号[subMchNo]参数"); + } + } + + /** + * 拉卡拉查询结算信息接口 + * + * @param settleRq + * @param isvParams + * @return + */ + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, LklspayIsvParams isvParams) { + super.preSettleCheck(settleRq); + if (StringUtils.isBlank(settleRq.getMercNo())) { + throw new BizException("缺失商户号"); + } + JSONObject bizData = new JSONObject(); + bizData.put("merchantNo", settleRq.getMercNo()); + bizData.put("startDate", DateUtil.format(settleRq.getStartDate(), DatePattern.PURE_DATE_PATTERN)); + bizData.put("endDate", DateUtil.format(settleRq.getEndDate(), DatePattern.PURE_DATE_PATTERN)); + bizData.put("page", settleRq.getPage()); + bizData.put("size", settleRq.getSize()); + JSONObject respData = LklspayKit.reqSettle(LklPayMethod.Api.SETTLE_QUERY, bizData, isvParams); + JSONArray resultList = respData.getJSONArray("respData"); + if(resultList.isEmpty()){ + return null; + } + //拉卡拉只支持单商户结算记录查询 + List result = new ArrayList<>(1); + for (Object item:resultList) { + JSONObject respBizData = (JSONObject)item; + JSONObject stlData = new JSONObject(); + stlData.put("billNo", respBizData.getString("payRecordId")); + stlData.put("accountName", respBizData.getString("accountName")); + stlData.put("accountNo", respBizData.getString("accountNo")); + stlData.put("bankName", respBizData.getString("accountBranchBank")); + stlData.put("channelState", respBizData.getString("chnlRespCode")); + stlData.put("remark", respBizData.getString("chnlRespMsg")); + String stlAmt = respBizData.getString("transferMoneyAmount"); + if (StringUtils.isNotBlank(stlAmt)) { + boolean val = stlAmt.contains(","); + if (val) { + stlAmt = stlAmt.replace(",", ""); + } + stlData.put("settleAmt", new BigDecimal(stlAmt).multiply(BigDecimal.valueOf(100))); + } +// String feeAmt = respBizData.getString("feeAmt"); +// if (StringUtils.isNotBlank(feeAmt)) { +// boolean val = feeAmt.contains(","); +// if (val) { +// feeAmt = feeAmt.replace(",", ""); +// } +// long fee = new BigDecimal(feeAmt).multiply(BigDecimal.valueOf(100)).longValue(); +// if( fee > 0L){ +// stlData.put("fee",fee); +// } +// } + String payDate = respBizData.getString("transferMoneyDate"); + stlData.put("settleDate", payDate); + stlData.put("settleTime", payDate + " " + respBizData.getString("transferMoneyTime")); + SettleState state = SettleState.getVal(respBizData.getString("transferMoneyStatus")); + switch (state) { + case PAY_SUCCESS: + stlData.put("state", SettleInfo.SUCCESS); + break; + case PAY_FAIL: + stlData.put("state", SettleInfo.FAIL); + break; + case PAY_PROGRESS: + stlData.put("state", SettleInfo.PROGRESS); + break; + case PAY_EZ: + stlData.put("state", SettleInfo.OTHER); + break; + default: + stlData.put("state", SettleInfo.WAIT); + break; + } + stlData.put("channelState", state.getState()); + stlData.put("extra", respBizData.toString()); + result.add(stlData); + } + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState { + + PAY_INIT("00", "初始登记"), + + PAY_PROGRESS("01", "付款中"), + + PAY_SUCCESS("02", "付款成功"), + + PAY_FAIL("03", "付款失败"), + + PAY_EZ("EZ", "状态未明"), + + PAY_AUDIT("07", "审核中"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state) { + SettleState[] values = values(); + for (SettleState val : values) { + if (val.getState().equals(state)) { + return val; + } + } + return PAY_INIT; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApplymentService.java new file mode 100644 index 0000000..c4b7e16 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayMchApplymentService.java @@ -0,0 +1,576 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.stream.StreamUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.LklspayApplymentInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.db.entity.BankBranchLkl; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.LocationCacheService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.mapper.BankBranchLklMapper; +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklMercInfoConn; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklTkReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class LklspayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private LocationCacheService locationCacheService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private BankBranchLklMapper bankBranchLklMapper; + + @Autowired + private Configuration configuration; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public 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); + + LklspayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), LklspayApplymentInfo.class); + applymentInfo.saveCheck(); + + Assert.notNull(applymentInfo.getAreaName(), "经营地区名称[areaName]不能为空"); + Assert.isFalse(applymentInfo.getAreaName().isEmpty(), "经营地区名称[areaName]不能为空"); + + result.setSettlementType(applymentInfo.getSettleType()); + + return result; + } + + private static LklMercInfoConn.Attachment getAttachment(LklspayIsvParams isvParams, File file, String imgType) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, file, imgType); + LklMercInfoConn.Attachment attachmentItem = new LklMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private static LklMercInfoConn.Attachment getAttachment(LklspayIsvParams isvParams, String fileUrl, String imgType) { + JSONObject imgUploadResult = LklspayKit.uploadRequest(isvParams, fileUrl, imgType); + LklMercInfoConn.Attachment attachmentItem = new LklMercInfoConn.Attachment(); + attachmentItem.setId(imgUploadResult.getString("url")); + attachmentItem.setType(imgType); + return attachmentItem; + } + + private File writeHtml(Template template, Map data) throws IOException, TemplateException { + String fileName = UUID.randomUUID().toString(); + File htmlFile = new File(FileUtil.getTmpDir(), fileName + ".html"); + FileWriter sw = new FileWriter(htmlFile); + log.info("生成协议html, 地址:{}, 参数:{} ", htmlFile.getAbsolutePath(), data); + template.process(data, sw); + + return htmlFile; + } + + private static File createAgreementPicture(File htmlFile) throws IOException { + File outputFile = new File(FileUtil.getTmpDir(), htmlFile.getName() + ".jpg"); + log.info("生成图片开始, HTML地址 {}, 图片地址:{}", htmlFile.getAbsolutePath(), outputFile.getAbsolutePath()); + String commandProcess = "wkhtmltoimage --width 400 --quality 94 " + htmlFile.getPath() + " " + outputFile.getPath(); + log.info("协议执行Process command:{}", commandProcess); + long startTime = System.currentTimeMillis(); //获取开始时间 + Process process = Runtime.getRuntime().exec(commandProcess); + try { + int exitVal = process.waitFor(); + log.info("协议html转换png结果:{}", exitVal); + } catch (InterruptedException e) { + log.info("协议html转换png错误", e); + Thread.currentThread().interrupt(); + throw new IOException(e); + } + long endTime = System.currentTimeMillis(); //获取结束时间 + log.info("程序运行时间: " + (endTime - startTime) + "ms"); + log.info("生成图片结束,地址: {}", outputFile.getPath()); + Thumbnails.of(outputFile).scale(1).outputQuality(0.9).toFile(outputFile); + return outputFile; + } + + private String getEndDate(String endDate) { + if ("长期".equals(endDate)) { + return "2099-12-31"; + } + + return endDate; + } + + private LklMercInfoConn getLklData(LklspayApplymentInfo applymentInfo, LklspayIsvParams isvParams) { + LklMercInfoConn mercInfo = new LklMercInfoConn(); + mercInfo.setUserNo(Long.parseLong(isvParams.getUserNo())); + mercInfo.setEmail("18062761507@163.com"); + mercInfo.setBusiCode(LklpayConst.BIZ_CODE_SCAN); + + if (com.jeequan.jeepay.core.entity.MchApplyment.MERCHANT_TYPE_PERSONAL == applymentInfo.getMerchantType()) { + mercInfo.setMerType("TP_PERSONAL"); + mercInfo.setMerRegName(applymentInfo.getMchFullName()); + } else { + mercInfo.setMerType("TP_MERCHANT"); + String mchFullName = applymentInfo.getMchFullName(); + if (mchFullName.length() > 20) { + // 字数过长,商户商户全称 + mercInfo.setMerRegName(applymentInfo.getMerRegName()); + } else { + mercInfo.setMerRegName(mchFullName); + } + } + + mercInfo.setMerName(applymentInfo.getMchShortName()); + mercInfo.setMerAddr(applymentInfo.getAddress()); + + mercInfo.setProvinceCode(applymentInfo.getMchAreaCode().getString(0)); + mercInfo.setCityCode(applymentInfo.getMchAreaCode().getString(1)); + mercInfo.setCountyCode(applymentInfo.getMchAreaCode().getString(2)); + + if (1 != applymentInfo.getMerchantType()) { + // 非小微商户提交营业执照信息 + mercInfo.setLicenseName(applymentInfo.getMchFullName()); + mercInfo.setLicenseNo(applymentInfo.getLicenseNo()); + mercInfo.setLicenseDtStart(applymentInfo.getLicenseEffectBegin()); + mercInfo.setLicenseDtEnd(getEndDate(applymentInfo.getLicenseEffectEnd())); + } + // 接口的经纬度字段是反的 + mercInfo.setLatitude(applymentInfo.getLatitude()); + mercInfo.setLongtude(applymentInfo.getLongtude()); + mercInfo.setSource("APP"); + + Assert.notNull(applymentInfo.getMccCode(), "缺少mcc编码信息"); + String[] mccInfo = applymentInfo.getMccCode().split("_"); + if (mccInfo.length != 2) { + throw new BizException("mcc数据异常"); + } + mercInfo.setBusinessContent(mccInfo[0]); + mercInfo.setLarName(applymentInfo.getIdcardName()); + mercInfo.setLarIdType("01"); + mercInfo.setLarIdCard(applymentInfo.getIdcardNo()); + mercInfo.setLarIdCardStart(applymentInfo.getIdcardEffectBegin()); + mercInfo.setLarIdCardEnd(getEndDate(applymentInfo.getIdcardEffectEnd())); + mercInfo.setContactMobile(applymentInfo.getContactPhone()); + mercInfo.setContactName(applymentInfo.getContactName()); + + BankBranchLkl bankCodeLkl = bankBranchLklMapper.selectByContactLine(applymentInfo.getOpenningBankCode()); + Assert.notNull(bankCodeLkl, "未获取到支行信息,请重新选择支行信息"); + + mercInfo.setOpenningBankCode(bankCodeLkl.getContactLine()); + mercInfo.setOpenningBankName(bankCodeLkl.getBranchName()); + mercInfo.setClearingBankCode(bankCodeLkl.getClearNo()); + + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaCode(), "缺少支行地区编码信息"); + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaName(), "缺少支行地区信息"); + mercInfo.setSettleProvinceCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(0)); + mercInfo.setSettleProvinceName(applymentInfo.getSettAccountBankBranchAreaName().getString(0)); + mercInfo.setSettleCityCode(applymentInfo.getSettAccountBankBranchAreaCode().getString(1)); + mercInfo.setSettleCityName(applymentInfo.getSettAccountBankBranchAreaName().getString(1)); + mercInfo.setAccountNo(applymentInfo.getSettAccountNo()); + mercInfo.setAccountName(applymentInfo.getSettAccountName()); + mercInfo.setAccountType(applymentInfo.getSettAccType()); + mercInfo.setAccountIdType("01"); + mercInfo.setAccountIdCard(applymentInfo.getSettAccountIdcardNo()); + mercInfo.setAccountIdDtStart(applymentInfo.getSettAccountIdcardEffectBegin()); + mercInfo.setAccountIdDtEnd(getEndDate(applymentInfo.getSettAccountIdcardEffectEnd())); + + mercInfo.setBizContent(getFeeInfo(applymentInfo, isvParams)); + mercInfo.setSettleType(applymentInfo.getSettleType()); + mercInfo.setSettlementType("AUTOMATIC"); + + return mercInfo; + } + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + private LklMercInfoConn.BizContent getFeeInfo(LklspayApplymentInfo applymentInfo, LklspayIsvParams isvParams) { + Map map = new HashMap<>(); + + List paywayFeeList = applymentInfo.getPaywayFeeList(); + + for (PaywayFee paywayFee : paywayFeeList) { + boolean isYsfLevelFee = (paywayFee.getWayCode().startsWith("YSF_") || paywayFee.getWayCode().startsWith("UP_")) + && PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) + && CollUtil.isNotEmpty(paywayFee.getLevelList()); + if (isYsfLevelFee) { + // 借记卡费率 + PaywayFee paywayFeeDebitCard = paywayFee.getLevelList().get(0); + double topFee1 = (double) paywayFeeDebitCard.getMaxFee() / 100L; + map.put("YSF_DISCOUNT_DEBIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_DEBIT_FEE", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee1)); + + PaywayFee paywayFee2DebitCard = paywayFee.getLevelList().get(1); + double topFee2 = (double) paywayFee2DebitCard.getMaxFee() / 100L; + map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", 0.5d, topFee2)); +// map.put("DEBIT_CARD", new LklMercInfoConn.Fee("DEBIT_CARD", Double.parseDouble(convertRate(paywayFeeDebitCard.getFeeRate())), topFee2)); + } + + PaywayFee creditCardPaywayFee = paywayFee.getCreditCardPaywayFee(); + if (creditCardPaywayFee != null && CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()) && (CollUtil.isNotEmpty(creditCardPaywayFee.getLevelList()))) { + PaywayFee paywayFeeCrebitCard = creditCardPaywayFee.getLevelList().get(0); + map.put("YSF_DISCOUNT_CREDIT_FEE", new LklMercInfoConn.Fee("YSF_DISCOUNT_CREDIT_FEE", Double.parseDouble(convertRate(paywayFeeCrebitCard.getFeeRate())), null)); + + PaywayFee paywayFee2CrebitCard = creditCardPaywayFee.getLevelList().get(1); + map.put("CREDIT_CARD", new LklMercInfoConn.Fee("CREDIT_CARD", Double.parseDouble(convertRate(paywayFee2CrebitCard.getFeeRate())), null)); + + } + + if (paywayFee.getWayCode().startsWith("WX_")) { + map.put("WECHAT", new LklMercInfoConn.Fee("WECHAT", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + + if (paywayFee.getWayCode().startsWith("ALI_")) { + map.put("ALIPAY", new LklMercInfoConn.Fee("ALIPAY", Double.parseDouble(convertRate(paywayFee.getFeeRate())), null)); + } + + if ("D0".equals(paywayFee.getWayCode())) { + double d0Rate = Double.parseDouble(convertRate(paywayFee.getFeeRate())); + // 扫码d0费率 + map.put("SCAN_PAY_SECOND", new LklMercInfoConn.Fee("SCAN_PAY_SECOND", d0Rate, null)); + // 刷卡D0费率 + map.put("CARD_SECOND", new LklMercInfoConn.Fee("CARD_SECOND", d0Rate, null)); + } + } + + // 扫码d0费率 + map.putIfAbsent("SCAN_PAY_SECOND", new LklMercInfoConn.Fee("SCAN_PAY_SECOND", 0.1d, null)); + // 刷卡D0费率 + map.putIfAbsent("CARD_SECOND", new LklMercInfoConn.Fee("CARD_SECOND", 0.1d, null)); + + LklMercInfoConn.BizContent bizContent = new LklMercInfoConn.BizContent(); + + String[] mccInfo = applymentInfo.getMccCode().split("_"); + bizContent.setMcc(mccInfo[1]); + // 25为B2B收银台 13位专业扫码 + bizContent.setActivityId(13); + bizContent.setTermNum("1"); + bizContent.setFees(new HashSet<>(map.values())); + + return bizContent; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment rejectModify(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment replenishInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return null; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment query(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject param = new JSONObject(); + param.put("customerNo", mchApplyment.getChannelApplyNo()); + JSONObject respData = LklspayKit.applymentRequest(LklTkReqMethod.AUDIT_STATUS_GET, isvParams, param); + JSONObject customer = respData.getJSONObject("customer"); + JSONArray terminalInfo = respData.getJSONArray("terminalInfo"); + + String status = customer.getString("customerStatus"); + String externalCustomerNo = customer.getString("externalCustomerNo"); + + if ("OPEN".equals(status)) { + JSONArray customerFeeList = respData.getJSONArray("customerFee"); + String termId = null; + // 将对应终端号下的终端id存下来 + for (int i = 0; i < customerFeeList.size(); i++) { + JSONObject customerFee = customerFeeList.getJSONObject(i); + String termNo = customerFee.getString("termNo"); + if (Objects.equals(termNo, customer.getString("termNo"))) { + termId = customerFee.getString("termId"); + break; + } + } + + mchApplyment.setSuccResParameter(customer.toString()); + Optional.ofNullable(termId).ifPresent(t -> customer.put("termId", t)); + + // 进件通过 + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS); + mchApplyment.setChannelMchNo(externalCustomerNo); + + subMchColl(mchApplyment); + } + + if ("REJECT".equals(status)) { + // 入网驳回 + String auditRemark = customer.getString("auditRemark"); + mchApplyment.setSuccResParameter(customer.toJSONString()); + mchApplyment.setApplyErrorInfo("[" + auditRemark + "]"); + mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return mchApplyment; + } + + @Override + public ApplymentSignInfo signInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return null; + } + + @Override + public void subMchColl(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject respData = LklspayKit.openRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = respData.getJSONArray("list"); + + if (subMercList == null) { + return; + } + + subMercList.forEach(item -> { + if (item instanceof JSONObject) { + JSONObject itemJson = (JSONObject) item; + processItem(itemJson, mchApplyment); + } + }); + } + + private void processItem(JSONObject itemJson, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + if ("UNIONPAY".equals(itemJson.getString("registerChannel"))) { + // 收银呗 + saveSubMerch(mchApplyment.getApplyId(), mchApplyment.getChannelMchNo(), itemJson, 1); + } else { + // 扫码付不存拉卡拉的子商户号 + saveSubMerch(mchApplyment.getApplyId(), mchApplyment.getChannelMchNo(), itemJson, 0); + } + +// if (!isLakalaSubMerchant(itemJson) && isWXZFRegisterType(itemJson)) { +// saveSubMerch(mchApplyment.getApplyId(), mchApplyment.getChannelMchNo(), itemJson, 0); +// } else { +// +// } + } + + /** + * 是否是拉卡拉的商户号 + */ + private boolean isLakalaSubMerchant(JSONObject itemJson) { + return "38630418".equals(itemJson.getString("channelId")); + } + + /** + * 是否是微信渠道 + */ + private boolean isWXZFRegisterType(JSONObject itemJson) { + return "WXZF".equals(itemJson.getString("registerType")); + } + + private void saveSubMerch(String mchApplyId, String channelMchNo, JSONObject itemJson, Integer isMainUse) { + String resultCode = itemJson.getString("resultCode"); + + MchSubInfoEntity subInfo = new MchSubInfoEntity(); + subInfo.setMchApplyId(mchApplyId); + subInfo.setChannelId(itemJson.getString("channelId")); + subInfo.setSubMchId(itemJson.getString("subMchId")); + subInfo.setRemark(itemJson.getString("resultMessage")); + subInfo.setChannelMchNo(channelMchNo); + subInfo.setMainUse(isMainUse); + subInfo.setSubMchWay(itemJson.getString("registerChannel")); + if ("ZFBZF".equals(itemJson.getString("registerType"))) { + subInfo.setSubMchType("ZFB"); + } else { + subInfo.setSubMchType("WX"); + } + + subInfo.setStatus(resultCode); + + try { + mchSubInfoService.save(subInfo); + } catch (DuplicateKeyException e) { + log.info("对应子商户信息已存在"); + } + } + + @Override + public void subMchCert(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + if ("WX".equals(mchSubInfo.getSubMchType())) { + wxAuthResult(mchApplyment, mchSubInfo); + } + + if ("ZFB".equals(mchSubInfo.getSubMchType())) { + zfbAuthResult(mchApplyment, mchSubInfo); + } + } + + public void wxAuthResult(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = LklspayKit.applymentRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = StreamUtil.of(subMercList) + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("WXZF")) + .collect(Collectors.toList()); + + // 拉卡拉开放平台商户号 + subMercList.getJSONObject(0); + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + + if (CharSequenceUtil.isEmpty(subMchId)) { + return; + } + + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "WECHAT") + .fluentPut("subMerchantId", subMchId); + + JSONObject respData = LklspayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.set(MchSubInfoEntity::getSubMchId, subMchId); + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } + + public void zfbAuthResult(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, MchSubInfo mchSubInfo) { + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + LklspayIsvParams isvParams = ((LklspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + JSONObject reqData = new JSONObject(); + String orderNo = DateUtil.format(new Date(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomString(RandomUtil.BASE_NUMBER, 8); + reqData.fluentPut("version", "1.0") + .fluentPut("orderNo", orderNo) + .fluentPut("orgCode", isvParams.getOrgCode()) + .fluentPut("merCupNo", mchApplyment.getChannelMchNo()); + + JSONObject req = LklspayKit.applymentRequest(LklTkReqMethod.QUERY_SUB_MERC, isvParams, reqData); + + JSONArray subMercList = req.getJSONArray("list"); + List filteredMercList = subMercList.stream() + .filter(t -> ((JSONObject) t).getString("registerChannel").equals("UNIONPAY")) + .filter(t -> ((JSONObject) t).getString("registerType").equals("ZFBZF")) + .collect(Collectors.toList()); + + // 拉卡拉开放平台商户号 + subMercList.getJSONObject(0); + String subMchId = ((JSONObject) filteredMercList.get(0)).getString("subMchId"); + + if (CharSequenceUtil.isEmpty(subMchId)) { + return; + } + + // 获取实名认证结果 + JSONObject reqData2 = new JSONObject(); + reqData2.fluentPut("merchantNo", mchApplyment.getChannelMchNo()) + .fluentPut("tradeMode", "ALIPAY") + .fluentPut("subMerchantId", subMchId); + + JSONObject respData = LklspayKit.openRequest(LklTkReqMethod.MCH_AUTH_STATUS, isvParams, reqData2); + + // 认证状态 + String authorizeState = respData.getString("checkResult"); + if ("UNAUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + + if ("AUTHORIZED".equals(authorizeState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + +// if ("CLOSED".equals(authorizeState)) { +// ums.setAliCertStatus("-1"); +// } + + String rejectReason = respData.getString("rejectReason"); + + uWrapper.set(MchSubInfoEntity::getRemark, rejectReason); + uWrapper.set(MchSubInfoEntity::getSubMchId, subMchId); + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderCloseService.java new file mode 100644 index 0000000..5f8e7e7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderCloseService.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 关闭订单接口实现类 + * + * @author crystal + * + */ +@Slf4j +@Service +public class LklspayPayOrderCloseService implements IPayOrderCloseService { + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + try { + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,payOrder.getClientIp()); + bizContent.put("origin_out_trade_no", payOrder.getPayOrderId()); + bizContent.put("origin_trade_no", payOrder.getPlatformMchOrderNo()); + + MchApplyment mchApplyment = mchAppConfigContext.getMchApplyment(); + JSONObject respBizData = LklspayKit.payRequest(LklPayMethod.Api.ORDER_CLOSE, mchApplyment, bizContent); + String trade_no = respBizData.getString("origin_trade_no"); + return ChannelRetMsg.confirmSuccess(trade_no); + }catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderQueryService.java new file mode 100644 index 0000000..5f4b003 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPayOrderQueryService.java @@ -0,0 +1,63 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LKlCardType; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklOrderStatus; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉查询订单 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class LklspayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,null); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("trade_no",payOrder.getChannelOrderNo()); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_QUERY, mchAppConfigContext.getMchApplyment(), bizContent); + LklOrderStatus state = LklOrderStatus.getVal(response.getString("trade_state")); + LKlCardType card_type = LKlCardType.getVal(response.getString("card_type")); + String drType = card_type.getType(); + switch (card_type){ + case LKL_ACCOUNT: + case ALI_OTHER: + drType = CS.DrType.OTHER.getType(); + break; + case DECP: + drType = CS.DrType.DCEP.getType(); + break; + } + ChannelRetMsg retMsg = ChannelRetMsg.confirmSuccess(response.getString("log_no"), response.getString("acc_trade_no"), response.getString("trade_no"),drType); + retMsg.setChannelUserId(response.getString("user_id2")); + switch (state){ + case SUCCESS: + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case CLOSE: + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + default: + retMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return retMsg; + } + return retMsg; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPaymentService.java new file mode 100644 index 0000000..b5c691c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayPaymentService.java @@ -0,0 +1,97 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + * 拉卡拉支付 + * @author crystal + */ +@Slf4j +@Service +public class LklspayPaymentService extends AbstractPaymentService { + + /** + * 拉卡拉花呗分期参数支持选项 + */ + public static final int[] ALI_HB_FQ_NUM_ARR = {3,6,12}; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + /** + * 统一返回参数解析 + * @param bizData + * @param channelRetMsg + */ + public JSONObject initResult(JSONObject bizData, ChannelRetMsg channelRetMsg) { + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelBizData(bizData); + if(LklPayMethod.NeedQuery.NO.getStatus().equals(bizData.getString("need_query"))){ + channelRetMsg.setNeedQuery(false); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + channelRetMsg.setChannelOrderId(bizData.getString("log_no")); + channelRetMsg.setPlatformOrderNo(bizData.getString("acc_trade_no")); + channelRetMsg.setPlatformMchOrderNo(bizData.getString("trade_no")); + JSONObject acc_resp_fields = bizData.getJSONObject("acc_resp_fields"); + if(acc_resp_fields != null){ + String userId = StringUtils.isNotEmpty(acc_resp_fields.getString("user_id")) ? acc_resp_fields.getString("user_id") : acc_resp_fields.getString("open_id"); + channelRetMsg.setChannelUserId(userId); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(acc_resp_fields.getString("prepay_id")); + jsapiMsg.setAppId(acc_resp_fields.getString("app_id")); + jsapiMsg.setPaySign(acc_resp_fields.getString("pay_sign")); + jsapiMsg.setTimeStamp(acc_resp_fields.getString("time_stamp")); + jsapiMsg.setNonceStr(acc_resp_fields.getString("nonce_str")); + jsapiMsg.setPayPackage(acc_resp_fields.getString("package")); + jsapiMsg.setSignType(acc_resp_fields.getString("sign_type")); + jsapiMsg.setRedirectUrl(acc_resp_fields.getString("redirect_url")); + channelRetMsg.setJsapiMsg(jsapiMsg); + } + return acc_resp_fields; + } + + public void preCheckAli(UnifiedOrderRQ rq) { + Integer hbFqNum = rq.getHbFqNum(); + if(hbFqNum != null){ + boolean isCheck = Arrays.stream(ALI_HB_FQ_NUM_ARR).anyMatch(num -> num == hbFqNum); + if(!isCheck){ + throw new BizException("支付宝支付花呗分期参数有误,仅可支持数值为"+StringUtils.join(ALI_HB_FQ_NUM_ARR,",") +"期"); + } + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayRefundService.java new file mode 100644 index 0000000..bd8d3a9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/LklspayRefundService.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.BizException; +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; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 拉卡拉 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class LklspayRefundService extends AbstractRefundService { + + @Autowired + private MchApplymentService mchApplymentService; + + @Override + public String getIfCode() { + return CS.IF_CODE.LKLSPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + ChannelRefundLimit refundLimit = this.isRefundLimit(payOrder.getSettleType(), payOrder.getMchExtNo()); + if(refundLimit.getIsPlatAccount()){ + if(ChannelRefundLimit.NO_OPEN == refundLimit.getBindStatus()){ + throw new BizException("拉卡拉通道D0退款需要先申请平台户退款"); + }else{ + this.checkPlatAccount(refundOrder); + } + } + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,refundOrder.getClientIp()); + bizContent.put("out_trade_no",refundOrder.getRefundOrderId()); + bizContent.put("refund_amount",refundOrder.getRefundAmount()); + bizContent.put("refund_reason",refundOrder.getRefundReason()); + bizContent.put("origin_out_trade_no",payOrder.getPayOrderId()); + bizContent.put("origin_trade_no",payOrder.getPlatformMchOrderNo()); + bizContent.put("origin_log_no",payOrder.getChannelOrderNo()); + JSONObject respBizData = LklspayKit.payRequest(LklPayMethod.Api.ORDER_REFUND, mchAppConfigContext.getMchApplyment(), bizContent); + channelRetMsg.setChannelBizData(respBizData); + channelRetMsg.setChannelOrderId(respBizData.getString("log_no")); + channelRetMsg.setPlatformMchOrderNo(respBizData.getString("trade_no")); + channelRetMsg.setPlatformOrderNo(respBizData.getString("acc_trade_no")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + return channelRetMsg; + } + + /** + * 退款权限 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + ChannelRefundLimit channelRefundLimit = new ChannelRefundLimit(false,true); + if(CS.SETTLEMENT_TYPE.D0.equals(settleType)){ + channelRefundLimit.setIsDefaultAccount(false); + channelRefundLimit.setIsPlatAccount(true); + MchApplyment applyment = mchApplymentService.getById(applyId); + if(MchApplyment.REFUND_WAY_PLATFORM.equals(applyment.getRefundWay())){ + channelRefundLimit.setBindStatus(ChannelRefundLimit.SUCCESS); + }else{ + channelRefundLimit.setBindStatus(ChannelRefundLimit.NO_OPEN); + } + } + return channelRefundLimit; + } + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + super.checkPlatAccount(refundOrder); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/README.MD b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/README.MD new file mode 100644 index 0000000..01e4b94 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/README.MD @@ -0,0 +1,4 @@ +## 使用汇拓客进件 + +拉卡拉汇拓客使用汇拓客的代码进行发起进件,使用拉卡拉开放平台的接口进行交易。 +故此代码中的支付代码与外部lklpay包中的交易服务代码是一致的。 \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/ILklTkReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/ILklTkReqMethod.java new file mode 100644 index 0000000..3c7ad7e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/ILklTkReqMethod.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import com.jeequan.jeepay.thirdparty.channel.lklpay.utils.LklpayConst; +import lombok.Getter; +import org.springframework.http.MediaType; + +@Getter +public abstract class ILklTkReqMethod { + + protected ILklTkReqMethod(String url, String templateWord, String method, String urlFlag) { + this(url, templateWord, method, false, urlFlag); + } + + protected ILklTkReqMethod(String url, String templateWord, String method, boolean encrypt, String urlFlag) { + this.url = url; + this.templateWord = templateWord; + this.method = method; + if (method.equals(LklpayConst.GET)) { + this.contentType = MediaType.APPLICATION_FORM_URLENCODED; + } else { + this.contentType = MediaType.APPLICATION_JSON; + } + this.encrypt = encrypt; + this.urlFlag = urlFlag; + } + + protected ILklTkReqMethod(String url, String templateWord, String method, MediaType contentType) { + this(url, templateWord, method, contentType, false); + } + + protected ILklTkReqMethod(String url, String templateWord, String method, MediaType contentType, boolean encrypt) { + this.url = url; + this.templateWord = templateWord; + this.method = method; + this.contentType = contentType; + this.encrypt = encrypt; + this.urlFlag = "saas"; + } + + private final String url; + + private final String templateWord; + + /** + * get或者post + */ + private final String method; + + private final MediaType contentType; + + private final boolean encrypt; + + /** + * 有saas和open两种 + */ + private final String urlFlag; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LKlCardType.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LKlCardType.java new file mode 100644 index 0000000..95bedd0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LKlCardType.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉交易卡类型枚举 + * @author crystal + * @date 2023/6/7 10:19 + */ +@Getter +@AllArgsConstructor +public enum LKlCardType { + + DEBIT("00","借记卡"), + + CREDIT("01","贷记卡"), + + BALANCE("02","零钱"), + + TOKIO("03","花呗"), + + ALI_OTHER("04","支付宝其他"), + + DECP("05","数字货币"), + + LKL_ACCOUNT("06","拉卡拉账户"), + + UNKNOWN("99","未知"); + + private final String type; + + private final String desc; + + public static LKlCardType getVal(String type){ + LKlCardType[] values = values(); + for (LKlCardType val:values) { + if(val.getType().equals(type)){ + return val; + } + } + return UNKNOWN; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMchReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMchReq.java new file mode 100644 index 0000000..343b3f4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMchReq.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.text.DateFormat; +import java.util.UUID; + +/** + * TODO + * 拉卡拉用户id相关操作 + * @author crystal + * @date 2023/11/25 15:39 + */ +@Data +public class LklMchReq { + + private String timestamp; + + private String rnd; + + private String ver; + + private String reqId; + + private JSONObject reqData; + + public LklMchReq(JSONObject reqData) { + this.timestamp = System.currentTimeMillis() + ""; + this.rnd = UUID.randomUUID().toString().replace("-",""); + this.reqId = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_MS_PATTERN); + this.ver = "1.0.0"; + this.reqData = reqData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMercInfoConn.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMercInfoConn.java new file mode 100644 index 0000000..7be0cbf --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklMercInfoConn.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.util.Set; + +@Setter +@Getter +public class LklMercInfoConn { + private Long userNo; + private String email; + private String busiCode; + private String merchantCode; + private String merRegName; + private String merType; + private String merName; + private String merAddr; + private String provinceCode; + private String cityCode; + private String countyCode; + private String licenseName; + private String licenseNo; + private String licenseDtStart; + private String licenseDtEnd; + private String latitude; + private String longtude; + private String source; + private String businessContent; + private String larName; + private String larIdType; + private String larIdCard; + private String larIdCardStart; + private String larIdCardEnd; + private String contactMobile; + private String contactName; + + private String openningBankCode; + + private String openningBankName; + + private String clearingBankCode; + + private String settleProvinceCode; + + private String settleProvinceName; + + private String settleCityCode; + + private String settleCityName; + + private String accountNo; + + private String accountName; + + private String accountType; + + private String accountIdCard; + + private String accountIdDtStart; + + private String accountIdDtEnd; + + private String accountIdType; + + private BizContent bizContent; + + private Set attchments; + private String settleType; + private String shopId; + private String settlementType; + private String regularSettlementTime; + + @Getter + @Setter + public static class BizContent { + + private String termNum; + + private Set fees; + + private String mcc; + + private Integer activityId; + } + + @Getter + @Setter + @AllArgsConstructor + public static class Fee { + + private String feeCode; + + private Double feeValue; + + private Double topFee; + + public Fee(String feeCode, String feeValue, Double topFee) { + this.feeValue = Double.parseDouble(feeValue); + this.feeCode = feeCode; + this.topFee = topFee; + } + } + + @Getter + @Setter + public static class Attachment { + + private String id; + + private String type; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklOrderStatus.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklOrderStatus.java new file mode 100644 index 0000000..e089af9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklOrderStatus.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉订单状态枚举 + * @author crystal + * @date 2023/11/25 13:58 + */ +@Getter +@AllArgsConstructor +public enum LklOrderStatus { + + INIT("INIT","初始化"), + CREATE("CREATE","下单成功"), + SUCCESS("SUCCESS","交易成功"), + DEAL("DEAL","交易处理中"), + UNKNOWN("UNKNOWN","未知状态"), + CLOSE("CLOSE","交易关闭"), + FAIL("FAIL","交易失败"), + PART_REFUND("PART_REFUND","部分退款"), + REFUND("REFUND","全部退款(或订单被撤销)"); + + private final String status; + + private final String desc; + + public static LklOrderStatus getVal(String status) { + LklOrderStatus[] orderStatuses = values(); + for (LklOrderStatus orderStatuse : orderStatuses) { + if (orderStatuse.getStatus().equals(status)) { + return orderStatuse; + } + } + return DEAL; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayMethod.java new file mode 100644 index 0000000..cd4b92f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayMethod.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2023/6/2 18:17 + */ +public class LklPayMethod { + + public static final String DOMAIN = "https://s2.lakala.com"; + + /** + * 拉卡支付路径配置 + */ + @Getter + @AllArgsConstructor + public enum Api{ + TRANS_PREORDER(DOMAIN + "/api/v3/labs/trans/preorder","聚合主扫"), + TRANS_MICROPAY(DOMAIN + "/api/v3/labs/trans/micropay","聚合被扫"), + TRANS_QUERY(DOMAIN + "/api/v3/labs/query/tradequery","聚合扫码-交易查询"), + ORDER_CLOSE(DOMAIN + "/api/v3/labs/relation/close","聚合扫码-关单"), + ORDER_REVOKED(DOMAIN + "/api/v3/labs/relation/revoked","扫码-撤销"), + ORDER_REFUND(DOMAIN + "/api/v3/labs/relation/refund","扫码-退款交易"), + IDM_REFUND(DOMAIN + "/api/v3/labs/relation/idmrefund","商户订单退款"), + IDM_REFUND_QUERY(DOMAIN + "/api/v3/labs/query/idmrefundquery","商户订单退款查询"), + USERID_QUERY(DOMAIN + "/api/v2/saas/query/wx_openid_query","获取用户ID"), + CASHIER_ORDER(DOMAIN + "/api/v3/ccss/counter/order/create","聚合收银台"), + CASHIER_QUERY(DOMAIN + "/api/v3/ccss/counter/order/query","聚合收银台订单查询"), + + MERC_LEDGER_OPEN(DOMAIN + "/api/v2/mms/openApi/ledger/applyLedgerMer","商户分账申请开通"), + MERC_LEDGER_CHANGE(DOMAIN + "/api/v2/mms/openApi/ledger/modifyLedgerMer","商户分账信息变更"), + MERC_LEDGER_QUERY(DOMAIN + "/api/v2/mms/openApi/ledger/queryLedgerMer","商户分账信息查询"), + + SETTLE_QUERY(DOMAIN + "/api/v2/searcher/transferMoney/queryTransferMoney","结算信息查询"), + + ORDER_FEE_QUERY(DOMAIN + "/api/v3/lams/merchant/query_trans","商户计费查询"), + UPLOAD(DOMAIN + "/api/v2/mms/openApi/uploadFile","附件上传"), + + UNIFY_REFUND(DOMAIN + "/api/v3/lams/trade/trade_refund","统一退货"), + UNIFY_REFUND_QUERY(DOMAIN + "/api/v3/lams/trade/trade_refund_query","退货查询"), + WECHAT_PARAMS_CONFIG_URL(DOMAIN + "/api/v2/mms/openApi/wechatParamConf","微信参数配置"), + + DEVICE_SPEAKER_BOX_ACTIVATE_URL(DOMAIN + "/api/v2/iot/cloud/device/activate","码牌音响激活"), + DEVICE_SPEAKER_BOX_DEACTIVATE_URL(DOMAIN + "/api/v2/iot/cloud/device/deactivate","码牌音响反激活"), + DEVICE_SPEAKER_BOX_ACTIVATE_STATUS_QUERY_URL(DOMAIN + "/api/v2/iot/cloud/device/activate/status","码牌音箱激活状态查询"), + DEVICE_SPEAKER_BOX_PUSH_QRCODE_URL(DOMAIN + "/api/v2/iot/cloud/pushQrcode","推送收款二维码至设备"), + DEVICE_SPEAKER_BOX_QUERY_SN_URL(DOMAIN + "/v2/iot/cloud/query/activate/by/mt","商终查询激活的SN"), + ; + + private final String url; + private final String desc; + } + + + @Getter + @AllArgsConstructor + public enum NeedQuery{ + YES("1","订单处理中需要查询"), + NO("0","不需要主动查询"),; + private final String status; + private final String desc; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayThirdReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayThirdReq.java new file mode 100644 index 0000000..2e66a97 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklPayThirdReq.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * 拉卡拉公共支付请求参数 + * @author crystal + * @date 2023/6/2 17:48 + */ +@Data +@NoArgsConstructor +public class LklPayThirdReq { + + public static final String VERSION = "3.0"; + + /** + * 请求时间,格式yyyyMMddHHmmss + */ + private String req_time; + + /** + * 3.0 + */ + private String version; + + /** + * 开放平台APPID + */ + private String out_org_code; + + /** + * 参见各个接口的请求参数格式 + */ + private Object req_data; + + public LklPayThirdReq(String out_org_code , Object req_data) { + this(out_org_code,VERSION); + this.req_data = req_data; + } + + public LklPayThirdReq(String out_org_code , String version, Object req_data) { + this(out_org_code,version); + this.req_data = req_data; + } + + public LklPayThirdReq(String out_org_code, String version) { + this.out_org_code = out_org_code; + this.version = version; + this.req_time = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_FORMAT); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklSettleReq.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklSettleReq.java new file mode 100644 index 0000000..5217a32 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklSettleReq.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.util.UUID; + +/** + * TODO + * 拉卡拉结算信息请求参数封装 + * @author crystal + * @date 2023/12/7 11:16 + */ +@Data +public class LklSettleReq { + + private Long timestamp; + + private String ver; + + private String reqId; + + private JSONObject reqData; + + public LklSettleReq(JSONObject bizData) { + this.timestamp = System.currentTimeMillis(); + this.reqId = DateUtil.format(new DateTime(), DatePattern.PURE_DATETIME_MS_PATTERN); + this.ver = "1.0.0"; + this.reqData = bizData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTkReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTkReqMethod.java new file mode 100644 index 0000000..7f3576b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTkReqMethod.java @@ -0,0 +1,64 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + + +import com.jeequan.jeepay.thirdparty.channel.lklspay.util.LklspayConst; +import org.springframework.http.MediaType; + +import static com.jeequan.jeepay.thirdparty.channel.lklspay.util.LklspayConst.*; + +public final class LklTkReqMethod extends ILklTkReqMethod { + + /** + * 拉卡拉平台公钥 + */ + public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHB7j7gG3ioLnnr7bsuEXTAh/8YSxSp4lQIYGW9gX0Ikgz9JqARdg4iEnU6tgNirxA6Jdg0AWgLJQxQBEZMkwyK2ZfYgesYhlJkv6WVC8v5OkOrhA9NSQ3iS6JsYegsZO0GJSTtLQaTOF8WobPYe5NI+eWU1fRz2ZyxlWlKshBeQIDAQAB"; + + /** + * 拉卡拉roshang机构私钥 + */ + public static final String PRI_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIcHuPuAbeKgueevtuy4RdMCH/xhLFKniVAhgZb2BfQiSDP0moBF2DiISdTq2A2KvEDol2DQBaAslDFAERkyTDIrZl9iB6xiGUmS/pZULy/k6Q6uED01JDeJLomxh6Cxk7QYlJO0tBpM4Xxahs9h7k0j55ZTV9HPZnLGVaUqyEF5AgMBAAECgYAmugRHvXHGiapH1JF2GvOLrRRXYddAbWRoYvOzxCO4/QwQOpsFJwL4U745HpGQcLXFN/ASiBbU9XQbG/DLdS182qAjvdZVJOA2e3H3LhpY3D8ec3webO+0nGk6e4oWGG1efJLM88Nb0FtQiQ0E6z17Paw5AGvxMVBPbL5SoQfq8QJBANHQmvFkAWlBL2XTLPUXaj+NAJzolE90ctAquxfDcTtfEXv0JitC5bwTg87uNl7n4PUTmtMDIkse+D5vQ2CIF78CQQCkwOIMzedKtWhOEbdGxiz1Y/jkuA8yF7HREeC7X2Av0z2Gi3yltoJd0s6zLn+6zowQp1O/5U6ifrYCIObWlTTHAkA0WOZ/eWL8vr2zmvdpgtkIWAaiH0j5deU7WJ3rNODoXjS/h0+KlZs5zGijVT2Nei7fFnAXW33P3j8zXJEj4XCDAkAcrG0rKVLNz9C9dZveN3NvqdyRge8zGqiZ6HCia7ED4dHdbr1c4ezCg4Px72/PhU8fPt/2j+Qlp8PpjuxeAE3VAkBqUiVV9XZptFEXa/77rgHP3SWrC3TcrrS5jtNTGfA4VISV95YXnZzWjYfpgs2WoxdAXjsrM5TB7L3V4um4o6Dp"; + + public static final ILklTkReqMethod TOKEN_AUDIT = new LklTkReqMethod("https://tkapi.lakala.com/auth/oauth/token", null, POST, MediaType.APPLICATION_FORM_URLENCODED); + public static final ILklTkReqMethod AUDIT = new LklTkReqMethod("https://htkactvi.lakala.com/registration/merchant", null, POST); + public static final ILklTkReqMethod SUB_MERC_LIST = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/submer", null, POST, true); + + public static final ILklTkReqMethod AUDIT_STATUS_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/info", null, POST, true); + public static final ILklTkReqMethod TOKEN_EDIT = new LklTkReqMethod("https://htkapi.lakala.com/auth/oauth/token", null, POST, MediaType.APPLICATION_FORM_URLENCODED); + public static final ILklTkReqMethod RATE_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/fee/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, GET); + public static final ILklTkReqMethod RATE_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/fee/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, POST, EDIT); + public static final ILklTkReqMethod SETTLE_GET = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/settle/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, GET); + public static final ILklTkReqMethod SETTLE_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/settle/" + CUSTOMER_NO_PLACE_HOLDER, CUSTOMER_NO_PLACE_HOLDER, POST); + public static final ILklTkReqMethod BASE_INFO_CHANGE = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/channel/customer/update/basic", null, POST, EDIT); + public static final ILklTkReqMethod CHANGE_STATUS_GET = new LklTkReqMethod("https://htkapi.lakala.com/api/customer/update/review", null, GET, EDIT); + public static final ILklTkReqMethod UPLOAD = new LklTkReqMethod("https://htkactvi.lakala.com/registration/file/upload", null, POST); + + public static final ILklTkReqMethod ADD_TERM = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/addTerm", null, POST); + public static final ILklTkReqMethod MCH_AUTH_STATUS = new LklTkReqMethod("https://s2.lakala.com/api/v2/mms/sme/mrchAuthStateQuery", null, POST); + + /** + * 拉卡拉开放平台接口,用于查询汇拓客对应的开放平台子商户号 + */ + public static final ILklTkReqMethod QUERY_SUB_MERC = new LklTkReqMethod("https://s2.lakala.com/api/v2/mms/openApi/querySubMerInfo", null, POST); + + /** + * 复议提交 + */ + public static final ILklTkReqMethod AUDIT_RETRY = new LklTkReqMethod("https://tkapi.lakala.com/htkmerchants/open/merchant/reconsider/submit", null, POST); + + private LklTkReqMethod(String url, String templateWord, String method, MediaType contentType) { + super(url, templateWord, method, contentType); + } + + + private LklTkReqMethod(String url, String templateWord, String method) { + super(url, templateWord, method, LklspayConst.AUDIT); + } + + private LklTkReqMethod(String url, String templateWord, String method, String urlFlag) { + super(url, templateWord, method, urlFlag); + } + + private LklTkReqMethod(String url, String templateWord, String method, boolean encrypt) { + super(url, templateWord, method, encrypt, LklspayConst.AUDIT); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTradeStatus.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTradeStatus.java new file mode 100644 index 0000000..358acd1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/model/LklTradeStatus.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 拉卡拉交易状态枚举 + * @author crystal + * @date 2023/6/7 10:19 + */ +@Getter +@AllArgsConstructor +public enum LklTradeStatus { + + INIT("INIT","初始化"), + + CREATE("CREATE","下单成功"), + + SUCCESS("SUCCESS","交易成功"), + + FAIL("FAIL","交易失败"), + + DEAL("DEAL","交易处理中"), + + UNKNOWN("UNKNOWN","未知状态"), + + CLOSE("CLOSE","交易关闭"), + + PART_REFUND("PART_REFUND","部分退款"), + + REFUND("REFUND","退款成功"), + + REVOKED("REVOKED","订单撤销"); + + private final String tradeStatus; + + private final String desc; + + public static LklTradeStatus getVal(String tradeStatus){ + LklTradeStatus[] values = values(); + for (LklTradeStatus val:values) { + if(val.getTradeStatus().equals(tradeStatus)){ + return val; + } + } + return UNKNOWN; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliBar.java new file mode 100644 index 0000000..9611161 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliBar.java @@ -0,0 +1,78 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + + +/** + * 拉卡拉 支付宝 条码支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Service("lklspayPaymentByAliBarService") +public class AliBar extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("auth_code",bizRQ.getAuthCode()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + bizContent.put("scan_type",bizRQ.getScanType()); + JSONObject acc_busi_fields = new JSONObject(); + Integer hbFqNum = bizRQ.getHbFqNum(); + if(hbFqNum != null){ + JSONObject extend_params = new JSONObject(); + extend_params.put("hb_fq_num",hbFqNum); + extend_params.put("hb_fq_seller_percent",0); + acc_busi_fields.put("extend_params",extend_params); + } + Integer limitPay = bizRQ.getLimitPay(); + if(limitPay != null && limitPay == 1){ + acc_busi_fields.put("disable_pay_channels","credit_group"); + } + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_MICROPAY, mchAppConfigContext.getMchApplyment(), bizContent); + this.initResult(response,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliJsapi.java new file mode 100644 index 0000000..43d9ca0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliJsapi.java @@ -0,0 +1,83 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉支付宝jsapi支付 + */ +@Slf4j +@Service("lklspayPaymentByAliJsapiService") +public class AliJsapi extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("remark",payOrder.getBuyerRemark()); + bizContent.put("account_type", "ALIPAY"); + bizContent.put("trans_type","51"); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + JSONObject acc_busi_fields = new JSONObject(); + Integer hbFqNum = bizRQ.getHbFqNum(); + if(hbFqNum != null){ + JSONObject extend_params = new JSONObject(); + extend_params.put("hb_fq_num",hbFqNum); + extend_params.put("hb_fq_seller_percent",0); + acc_busi_fields.put("extend_params",extend_params); + } + Integer limitPay = bizRQ.getLimitPay(); + if(limitPay != null && limitPay == 1){ + acc_busi_fields.put("disable_pay_channels","credit_group"); + } + acc_busi_fields.put("user_id",bizRQ.getBuyerUserId()); + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + res.setAlipayTradeNo(payInfo.getString("prepay_id")); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(payInfo.getString("prepay_id")); + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliLite.java new file mode 100644 index 0000000..aaa6790 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliLite.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 拉卡拉小程序支付 + * + * @author crystal + * + * @date 2021/6/8 18:08 + */ +@Service("lklspayPaymentByKqAliLiteService") //Service Name需保持全局唯一性 +@Slf4j +public class AliLite extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]参数不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("remark",payOrder.getBuyerRemark()); + bizContent.put("account_type", "ALIPAY"); + bizContent.put("trans_type","51"); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + JSONObject acc_busi_fields = new JSONObject(); + Integer hbFqNum = bizRQ.getHbFqNum(); + if(hbFqNum != null){ + JSONObject extend_params = new JSONObject(); + extend_params.put("hb_fq_num",hbFqNum); + extend_params.put("hb_fq_seller_percent",0); + acc_busi_fields.put("extend_params",extend_params); + } + Integer limitPay = bizRQ.getLimitPay(); + if(limitPay != null && limitPay == 1){ + acc_busi_fields.put("disable_pay_channels","credit_group"); + } + acc_busi_fields.put("user_id",bizRQ.getBuyerUserId()); + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + res.setAlipayTradeNo(payInfo.getString("prepay_id")); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(payInfo.getString("prepay_id")); + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliQr.java new file mode 100644 index 0000000..4f9b838 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/AliQr.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉 支付宝NATIVE + * + * @author xiaoyu + * + * @date 2022/5/24 17:38 + */ +@Service("lklspayPaymentByAliQrService") //Service Name需保持全局唯一性 +public class AliQr extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliQrOrderRQ bizRQ = (AliQrOrderRQ)rq; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + AliQrOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("account_type", "NATIVE"); + bizContent.put("trans_type","41"); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject acc_busi_fields = new JSONObject(); + Integer hbFqNum = bizRQ.getHbFqNum(); + if(hbFqNum != null){ + JSONObject extend_params = new JSONObject(); + extend_params.put("hb_fq_num",hbFqNum); + extend_params.put("hb_fq_seller_percent",0); + acc_busi_fields.put("extend_params",extend_params); + } + Integer limitPay = bizRQ.getLimitPay(); + if(limitPay != null && limitPay == 1){ + acc_busi_fields.put("disable_pay_channels","credit_group"); + } + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + String qrCdUrl = payInfo.getString("code"); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdUrl)); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdUrl)); + }else{ + jsapiMsg.setQrCodeUrl(qrCdUrl); + res.setCodeUrl(qrCdUrl); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/DcepBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/DcepBar.java new file mode 100644 index 0000000..f453ab4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/DcepBar.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.DcepBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉数字人民币条码支付 + * + * @author xiaoyu + * + * @date 2022/6/13 18:03 + */ +@Slf4j +@Service("lklspayPaymentByDcepBarService") //Service Name需保持全局唯一性 +public class DcepBar extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + DcepBarOrderRQ bizRQ = (DcepBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + DcepBarOrderRQ bizRQ = (DcepBarOrderRQ) rq; + DcepBarOrderRS res = ApiResBuilder.buildSuccess(DcepBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("auth_code",bizRQ.getAuthCode()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_MICROPAY, mchAppConfigContext.getMchApplyment(), bizContent); + this.initResult(response,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/UpQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/UpQr.java new file mode 100644 index 0000000..23c5098 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/UpQr.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 银联NATIVE支付 + * @author crystal + */ +@Service("lklspayPaymentByUpQrService") //Service Name需保持全局唯一性 +@Slf4j +public class UpQr extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + UpQrOrderRQ bizRQ = (UpQrOrderRQ)rq; + // 构造函数响应数据 + UpQrOrderRS res = ApiResBuilder.buildSuccess(UpQrOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("account_type", "NATIVE"); + bizContent.put("trans_type","41"); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + String qrCdUrl = payInfo.getString("code"); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdUrl)); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdUrl)); + }else{ + jsapiMsg.setQrCodeUrl(qrCdUrl); + res.setCodeUrl(qrCdUrl); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxBar.java new file mode 100644 index 0000000..fb65e78 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxBar.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉 微信 条码支付 + * + * @author crystal + */ +@Slf4j +@Service("lklspayPaymentByWxBarService") //Service Name需保持全局唯一性 +public class WxBar extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 默认支付参数 + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("auth_code",bizRQ.getAuthCode()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject acc_busi_fields = new JSONObject(); + Integer limitPay = bizRQ.getLimitPay(); + if(limitPay != null && limitPay == 1){ + acc_busi_fields.put("limit_pay","no_credit"); + } + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + bizContent.put("sub_appid",bizRQ.getSubAppid()); + }else{ + bizContent.put("sub_appid",oauth2Params.getAppId()); + } + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_MICROPAY, mchAppConfigContext.getMchApplyment(), bizContent); + this.initResult(response,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxJsapi.java new file mode 100644 index 0000000..e7edbeb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxJsapi.java @@ -0,0 +1,110 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 拉卡拉支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/4/15 15:37 + */ +@Slf4j +@Service("lklspayPaymentByWxJsapiService") //Service Name需保持全局唯一性 +public class WxJsapi extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("account_type","WECHAT"); + bizContent.put("trans_type","51"); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject acc_busi_fields = new JSONObject(); + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + acc_busi_fields.put("sub_appid",bizRQ.getSubAppid()); + }else{ + acc_busi_fields.put("sub_appid",oauth2Params.getAppId()); + } + acc_busi_fields.put("user_id",bizRQ.getOpenid()); + if(bizRQ.getLimitPay() != null && bizRQ.getLimitPay() == 1){ + acc_busi_fields.put("limit_pay","no_credit"); + } + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + + public static void main(String[] args) { + String ss = "{\"merchant_no\":\"8225210899900F0\",\"out_trade_no\":\"P1742858341545418753\",\"trade_no\":\"20240104110113130266215741766678\",\"log_no\":\"66215741766678\",\"settle_merchant_no\":\"\",\"settle_term_no\":\"\",\"acc_resp_fields\":{\"code\":\"\",\"code_image\":\"\",\"prepay_id\":\"wx041839451311948c0cb2454b2063190000\",\"app_id\":\"wx45c4343397131a20\",\"pay_sign\":\"rkUQ35bhG9LBmAKF2X1LhSDSrvyCWOnt0+teVcJ6xD0l5fEC4zfhJ/PEhGIis3xoM4Smjp6WDt5P3q0Eh+dCF8DjYVk1FnYNrw2XuXJ1LLr9iyW5YCDKlzFrfacR+FtGKgipNcnCJZfd+OtB6g3Fi34aaYFJVfyDZ+hJt05tEe46nWUIjDV1EsjHG6WlAwPiJgbwKcCEZwUMRCOvKXPoXfkmQTGsySJN1Iiv37sTr9dwJ+cyFUu6G+fJneFg85uftnqfYw4x9JJc/wiBvE28z1eHTHDLg7RvI4GOarwMWhDaJF2rEqVmnSW8PZvYn/SXSSvW1CLSGBkThz/kp6f4pQ==\",\"time_stamp\":\"1704364785\",\"nonce_str\":\"c8a228e920bd46c6a5db3b5b2bdd4d9d\",\"package\":\"prepay_id=wx041839451311948c0cb2454b2063190000\",\"sign_type\":\"RSA\",\"redirect_url\":\"\",\"best_pay_info\":\"\"}}"; + JSONObject bizData = JSON.parseObject(ss); + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + WxJsapi jsapi = new WxJsapi(); + JSONObject payInfo = jsapi.initResult(bizData, channelRetMsg); + if(payInfo != null){ + JSONObject outPayInfo = new JSONObject(); + outPayInfo.put("appId",payInfo.getString("app_id")); + outPayInfo.put("nonceStr",payInfo.getString("nonce_str")); + outPayInfo.put("timeStamp",payInfo.getString("time_stamp")); + outPayInfo.put("package",payInfo.getString("package")); + outPayInfo.put("signType",payInfo.getString("sign_type")); + outPayInfo.put("paySign",payInfo.getString("pay_sign")); + outPayInfo.put("prepayId",payInfo.getString("prepay_id")); + res.setPayInfo(outPayInfo.toString()); + } + res.setChannelRetMsg(channelRetMsg); + + System.out.println("ret"+JSON.toJSONString(channelRetMsg)); + System.out.println("res"+JSON.toJSONString(res)); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxLite.java new file mode 100644 index 0000000..21a55ac --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/WxLite.java @@ -0,0 +1,83 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:52 + */ +@Slf4j +@Service("lklspayPaymentByWxLiteService") //Service Name需保持全局唯一性 +public class WxLite extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + // 设置请求参数 + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("account_type","WECHAT"); + bizContent.put("trans_type","71"); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("remark",payOrder.getBuyerRemark()); + JSONObject acc_busi_fields = new JSONObject(); + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + acc_busi_fields.put("sub_appid",bizRQ.getSubAppid()); + }else{ + acc_busi_fields.put("sub_appid",oauth2Params.getLiteAppId()); + } + acc_busi_fields.put("user_id",bizRQ.getOpenid()); + if(bizRQ.getLimitPay() != null && bizRQ.getLimitPay() == 1){ + acc_busi_fields.put("limit_pay","no_credit"); + } + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfBar.java new file mode 100644 index 0000000..5456db8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfBar.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 云闪付条码支付 + * @author crystal + */ +@Service("lklspayPaymentByYsfBarService") +public class YsfBar extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + YsfBarOrderRS res = ApiResBuilder.buildSuccess(YsfBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + LklspayKit.setPayParams(mchAppConfigContext, bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("auth_code",bizRQ.getAuthCode()); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + bizContent.put("remark",payOrder.getBuyerRemark()); + bizContent.put("scan_type",bizRQ.getScanType()); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_MICROPAY, mchAppConfigContext.getMchApplyment(), bizContent); + this.initResult(response,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfJsapi.java new file mode 100644 index 0000000..257e5e2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/payway/YsfJsapi.java @@ -0,0 +1,73 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银联jsapi + * @author crystal + */ +@Service("lklspayPaymentByYsfJsapiService") +public class YsfJsapi extends LklspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getUserId())){ + throw new BizException("[userId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + LklspayKit.setPayParams(mchAppConfigContext,bizContent,payOrder.getClientIp()); + bizContent.put("out_trade_no",payOrder.getPayOrderId()); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("remark",payOrder.getBuyerRemark()); + bizContent.put("account_type", "UQRCODEPAY"); + bizContent.put("trans_type","51"); + bizContent.put("total_amount",payOrder.getFindAmt()); + bizContent.put("notify_url",getNotifyUrl()); + bizContent.put("settle_type","0"); + + JSONObject acc_busi_fields = new JSONObject(); + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + acc_busi_fields.put("timeout_express",expiredTime); + acc_busi_fields.put("user_id",bizRQ.getUserId()); + acc_busi_fields.put("front_url",bizRQ.getFrontUrl()); + acc_busi_fields.put("front_fail_url",bizRQ.getFrontFailUrl()); + bizContent.put("acc_busi_fields",acc_busi_fields); + JSONObject response = LklspayKit.payRequest(LklPayMethod.Api.TRANS_PREORDER, mchAppConfigContext.getMchApplyment(), bizContent); + JSONObject payInfo = this.initResult(response, channelRetMsg); + if(payInfo != null){ + res.setRedirectUrl(payInfo.getString("redirect_url")); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/util/LklspayConst.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/util/LklspayConst.java new file mode 100644 index 0000000..c500d79 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/lklspay/util/LklspayConst.java @@ -0,0 +1,53 @@ +package com.jeequan.jeepay.thirdparty.channel.lklspay.util; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LklspayConst { + + public static final Integer ACTIVITY_ID_WECHAT_PAY = 13; + + public static final Integer ACTIVITY_ID_B2B_SYT = 13; + + /** + * 专业扫码 + */ + public static final String BIZ_CODE_SCAN = "WECHAT_PAY"; + + /** + * B2B收银台 + */ + public static final String BIZ_CODE_B2B = "B2B_SYT"; + + public static final String POST = "POST"; + + public static final String GET = "GET"; + + public static final String AUDIT = "audit"; + public static final String EDIT = "edit"; + + public static final String CUSTOMER_NO_PLACE_HOLDER = "{customerNo}"; + + public static final String CUSTOMER_NO = "customerNo"; + + public static final String REVIEW_RELATED_ID = "reviewRelatedId"; + + public static final String ACCOUNT_NAME = "accountName"; + + public static final String ACCOUNT_NO = "accountNo"; + + public static final String BANK_NAME = "bankName"; + public static final String BANK_NO = "bankNo"; + public static final String CLEARING_BANK_NO = "clearingBankNo"; + + /** + * 变更通过 + */ + public static final String EDIT_PASS = "PASS"; + + /** + * 变更不通过 + */ + public static final String EDIT_UNPASS = "UNPASS"; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelNoticeService.java new file mode 100644 index 0000000..446e936 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelNoticeService.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 瑞银信 回调接口实现类 + */ +@Service +@Slf4j +public class RyxpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject reqParamJSON = getReqParamJSON(); + String payOrderId = reqParamJSON.getString("reqMsgId"); + return MutablePair.of(payOrderId, reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject respJson = (JSONObject) JSONObject.toJSON(params); + //验证签名 并且解析参数 + PayRespEntity notifyData = verifyParams(respJson, mchAppConfigContext, payOrder); + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(RyxpayKit.SUCCESS_CODE); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); + result.setChannelErrCode(notifyData.getRespCode()); + result.setChannelErrMsg(notifyData.getRespMsg()); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + result.setChannelUserId(notifyData.getData().getString("buyerId")); + result.setChannelOrderId(notifyData.getSmzfMsgId()); + //如果是支付宝 则需要去除前两位 + result.setPlatformOrderNo(notifyData.getData().getString("channelTradeNo")); + result.setPlatformMchOrderNo(notifyData.getChannelMsgId()); + String payType = notifyData.getData().getString("payType"); + if(StringUtils.isNotEmpty(payType)){ + switch (payType){ + case "1": + result.setDrType(CS.DrType.DEBIT.getType()); + break; + case "2": + result.setDrType(CS.DrType.CREDIT.getType()); + break; + default: + result.setDrType(CS.DrType.OTHER.getType()); + break; + } + }else{ + result.setDrType(CS.DrType.OTHER.getType()); + } + String respType = notifyData.getRespType(); + if(RyxpayKit.RESP_BIZ_FAIL.equals(respType)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else if(RyxpayKit.RESP_BIZ_ING.equals(respType)){ + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 解析瑞银信参数 + * @return + */ + public PayRespEntity verifyParams(JSONObject params, MchAppConfigContext mchAppConfigContext, PayOrder payOrder) { + String logPrefix = "【处理[瑞银信]支付回调】"; + log.info("{}回调参数: jsonParams:{}", logPrefix, params); + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), payOrder.getIfCode()); + return RyxpayKit.resultParamsDecode(params, isvParams); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelRefundNoticeService.java new file mode 100644 index 0000000..3e175a3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelRefundNoticeService.java @@ -0,0 +1,93 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 瑞银信退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class RyxpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject params = getReqParamJSON(); + // 接收返回参数 + String refundOrderId = params.getString("reqMsgId"); + return MutablePair.of(refundOrderId, params); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + // 获取请求参数 + JSONObject respJson = (JSONObject) params; + // 校验支付回调 + //验证签名 并且解析参数 + PayRespEntity notifyData = verifyParams(respJson, mchAppConfigContext); + // 验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(RyxpayKit.SUCCESS_CODE); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelErrCode(notifyData.getRespCode()); + result.setChannelErrMsg(notifyData.getRespMsg()); + result.setChannelUserId(notifyData.getData().getString("buyerId")); + result.setChannelOrderId(notifyData.getSmzfMsgId()); + //如果是支付宝 则需要去除前两位 + result.setPlatformOrderNo(notifyData.getData().getString("channelTradeNo")); + result.setPlatformMchOrderNo(notifyData.getChannelMsgId()); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + String respType = notifyData.getRespType(); + if(RyxpayKit.RESP_BIZ_FAIL.equals(respType)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else if(RyxpayKit.RESP_BIZ_ING.equals(respType)){ + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 处理瑞银信退款通知参数 + * @return + */ + public PayRespEntity verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + return RyxpayKit.resultParamsDecode(jsonParams, isvParams); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelUserService.java new file mode 100644 index 0000000..54065be --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayChannelUserService.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** +* 银盛 获取银联userId实现类 +* +* @author jmdhapy +* +* @date 2022/3/17 16:51 +*/ +@Service +@Slf4j +public class RyxpayChannelUserService implements IChannelUserService { + + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("redirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【瑞银信获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + JSONObject bizContent = new JSONObject(); + bizContent.put("merchantCode",mchAppConfigContext.getMchApplyment().getChannelMchNo()); + bizContent.put("payWay","UPZF"); + // 用户授权码 + bizContent.put("userAuthCode", userAuthCode); + // 银联支付标识 + bizContent.put("appUpIdentifier", appUpIdentifier); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF019, isvParams, bizContent, null, null); + String respType = response.getRespType(); + if(!RyxpayKit.RESP_BIZ_SUCCESS.equals(respType)){ + throw new BizException(response.getRespMsg()); + } + return response.getData().getString("userId"); + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayGetApplymentDataService.java new file mode 100644 index 0000000..d0ae90d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayGetApplymentDataService.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.db.entity.BankBranch; +import com.jeequan.jeepay.service.impl.BankBranchService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class RyxpayGetApplymentDataService implements IGetApplymentDataService { + + @Autowired + private BankBranchService bankBranchService; + + /** + * @cityCode 这里取城市名称. + */ + @Override + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { +// Assert.notBlank(bankName, "银行名称不能为空"); + Page page = new Page<>(); + bankBranchService.pageByArea(page, cityCode, bankName, branchName); + + return page.getRecords().stream().map( t -> ((JSONObject) JSON.toJSON(t))).collect(Collectors.toList()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..d2ece42 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchAlipayConfigService.java @@ -0,0 +1,81 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class RyxpayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + // 支付宝渠道拓展地址 + result.setSignUrl(isvParams.getAliUrl()); + // 图片类型 + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (StringUtils.isEmpty(mchApplyment.getChannelMchNo())) { + result.setErrInfo("随行付商户号为空"); + return result; + } + // 银盛商户号 + String mercId = suJson.getString("mercId"); + + LambdaQueryChainWrapper zfbSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + MchSubInfoEntity zfb = zfbSubInfoQuery.one(); + + if (zfb == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + zfb = zfbSubInfoQuery.one(); + } + + if (zfb == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if ("0".equals(zfb.getStatus())) { + result.setChannelSubMchId(zfb.getSubMchId()); + result.setState("当前通道暂不支持查询"); + } else { + result.setState("未报备"); + result.setErrInfo("[" + zfb.getRemark() + "]"); + return result; + } + + + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..dbbf8b2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchApplymentNotifyService.java @@ -0,0 +1,175 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.model.applyment.RyxpayApplymentInfo; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +/** + * 瑞银信通道回调处理只有商户进件回调,没有其他的回调 + */ +@Slf4j +@Service("ryxpayIsvmchApplymentNotifyService") +public class RyxpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Autowired + private RyxpayMchApplymentService ryxpayMchApplymentService; + + @Autowired + private RyxpayIsvmchModifyApplymentService ryxpayIsvmchModifyApplymentService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + // 这里只写走回调的情况, + JSONObject auditResult = requestKitBean.reqParam2JSON(); + String applicationId = auditResult.getString("orderId"); + + com.jeequan.jeepay.db.entity.MchApplyment mchApplyment = mchApplymentService.lambdaQuery() + .eq(com.jeequan.jeepay.db.entity.MchApplyment::getChannelApplyNo, applicationId) + .one(); + + return new MutablePair<>(mchApplyment.getApplyId(), auditResult); + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment) { + JSONObject auditResult = (JSONObject) params; + + MchModifyApplymentEntity modifyApplymentEntity = null; + + // 该判定是因为消息回来源不是源自通道方的直接通知,此处是通过rabbitmq的消息转发 + if (mchApplyment == null) { + String applicationId = auditResult.getString("orderId"); + + com.jeequan.jeepay.db.entity.MchApplyment dbMchApplyment = mchApplymentService.lambdaQuery() + .eq(com.jeequan.jeepay.db.entity.MchApplyment::getChannelApplyNo, applicationId) + .one(); + + modifyApplymentEntity = modifyApplymentService.getByOrderId(applicationId, CS.IF_CODE.RYXPAY); + + if (dbMchApplyment == null && modifyApplymentEntity == null) { + return new MutablePair<>(null, retOk(null)); + } + + if (dbMchApplyment != null) { + mchApplyment = mchInfoConverter.toModel(dbMchApplyment); + } + } + + if (mchApplyment != null) { + String taskStatus = auditResult.getString("status"); + String remark = auditResult.getString("memo"); + + MchApplyment result = new MchApplyment(); + result.setChannelVar1(auditResult.toString()); + result.setApplyId(mchApplyment.getApplyId()); + result.setRemark(remark); + + if ("3".equals(taskStatus)) { + String onlMerId = auditResult.getString("onlMerId"); + ryxpayMchApplymentService.subMchColl(mchApplyment, auditResult); + + result.setChannelMchNo(onlMerId); + result.setSuccResParameter(auditResult.toJSONString()); + result.setState(MchApplyment.STATE_SUCCESS); + + return new MutablePair<>(result, retOk(null)); + } else if ("5".equals(taskStatus)) { + // 待签约 + RyxpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), RyxpayApplymentInfo.class); + + String merName; + if (MchApplyment.MERCHANT_TYPE_PERSONAL == mchApplyment.getMerchantType()) { + merName = "商户" + applymentInfo.getIdcardName(); + } else { + merName = applymentInfo.getMchFullName(); + } + + try { + merName = URLEncoder.encode(merName, "UTF-8"); + } catch (UnsupportedEncodingException ignored) { + } + + String urlTemplate = "https://rjp.ruiyinxin.com/mims2/ruijiaSign/index.html?merInId=%s&merName=%s"; + String url = String.format(urlTemplate, auditResult.getString("merInId"), merName); + + JSONObject channelVar2 = new JSONObject(); + channelVar2.put("signUrl", url); + // 待签约状态 + result.setChannelVar1(auditResult.toJSONString()); + result.setChannelVar2(channelVar2.toJSONString()); + result.setState(MchApplyment.STATE_WAIT_SIGN); + + return new MutablePair<>(result, retOk(null)); + } else { + // 进件失败 + result.setApplyId(mchApplyment.getApplyId()); + result.setChannelVar1(auditResult.toString()); + result.setApplyErrorInfo("[" + remark + "]"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(result, retOk(null)); + } + } + + if (modifyApplymentEntity != null) { + // 结算信息变更回调 + String status = auditResult.getString("status"); + String memo = auditResult.getString("memo"); + + if ("3".equals(status)) { + modifyApplymentEntity.setState(MchApplyment.STATE_SUCCESS); + ryxpayIsvmchModifyApplymentService.localModifySettlement(new MutablePair<>(mchInfoConverter.toModel(modifyApplymentEntity), mchApplyment)); + } else { + modifyApplymentEntity.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + modifyApplymentEntity.setRemark(memo); + modifyApplymentService.updateById(modifyApplymentEntity); + } + + return new MutablePair<>(null, retOk(null)); + } + + return new MutablePair<>(null, retOk(null)); + } + + @Override + public ResponseEntity retOk(Object params) { + JSONObject result = new JSONObject(); + result.put("code", "0"); + result.put("msg", "通知成功"); + + return ResponseEntity.ok(result); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..bea2d67 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchModifyApplymentService.java @@ -0,0 +1,296 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.resource.BytesResource; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.RyxpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.RyxAccessResp; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import java.io.ByteArrayOutputStream; +import java.util.Objects; + +@Slf4j +@Service +public class RyxpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchModifyApplymentService mchModifyApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + RyxpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, RyxpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + RyxpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, RyxpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setAuthSettle(mchModifyData.getIllegal()); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setLetterOfAuthPic(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put("accessId", isvParams.getAccessId()); + param.put("merInId", JSON.parseObject(mchApplyment.getSuccResParameter()).getString("merInId")); + param.put("merName", mchModifyData.getMchShortName()); + + try { + RyxAccessResp ryxAccessResp = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_UPDATE_MERC_NAME, isvParams, param, null); + + if (RyxAccessResp.RESULT_OK.equals(ryxAccessResp.getCode())) { + return localModifyBase(mchDataPair); + } else { + resultModifyApplyment.setApplyErrorInfo("[" + ryxAccessResp.getMsg() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + String remark = "瑞银信基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("瑞银信基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + public byte[] getFileBytes(String imgUrl, String picType) { + Assert.notNull(imgUrl, "缺少类型为" + picType + "的图片"); + + // 下载文件 + byte[] imgFileByteArray = null; + try { + ByteArrayOutputStream baos = ImageUtils.compressNetPic(imgUrl, 2048 * 1024); + imgFileByteArray = baos.toByteArray(); + } catch (IORuntimeException e) { + e.printStackTrace(); + } + + return imgFileByteArray; + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + JSONObject otherParam = new JSONObject(); + + // 上传图片 + if ("B".equals(mchModifyData.getSettAccountType())) { + param.put("settleType", "3"); + otherParam.put("cardPic", new BytesResource(getFileBytes(mchModifyData.getSettAccountLicenseImg(), "开户许可证"))); + } else { + otherParam.put("cardPic", new BytesResource(getFileBytes(mchModifyData.getSettAccountLicenseImg(), "银行卡卡号面"))); + } + + if ("Y".equals(mchModifyData.getIllegal())) { + param.put("settleType", "2"); + // 非法人结算, 上传身份证图片 + otherParam.put("autPic", new BytesResource(getFileBytes(mchModifyData.getNonLegSettleAuthPic(), "授权结算函"))); +// String settlePersonIdcardPositive = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountIdcard1Img(), "07"); +// param.put("settlePersonIdcardPositive", settlePersonIdcardPositive); +// String settlePersonIdcardOpposite = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountIdcard2Img(), "08"); +// param.put("settlePersonIdcardOpposite", settlePersonIdcardOpposite); +// String letterOfAuthPic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getNonLegSettleAuthPic(), "26"); +// param.put("letterOfAuthPic", letterOfAuthPic); + } else { + param.put("settleType", "1"); + } + + if (mchApplyment.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + param.put("settleCredType", "0105"); + param.put("settleCredNo", mchModifyData.getSettAccountIdcardNo()); + } + + param.put("bankCard", mchModifyData.getSettAccountNo()); + param.put("headBankNo", mchModifyData.getBankCode()); + param.put("openBankChild", mchModifyData.getBankSubCode()); + String succResParameter = mchApplyment.getSuccResParameter(); + JSONObject succResJson = JSON.parseObject(succResParameter); + param.put("merInId", succResJson.getString("merInId")); + + try { + RyxAccessResp ryxAccessResp = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_UPDATE_SETTLE_CARD, isvParams, param, otherParam); + + if (RyxAccessResp.RESULT_OK.equals(ryxAccessResp.getCode())) { + resultModifyApplyment.setChannelApplyNo(ryxAccessResp.getResult().getString("orderId")); + resultModifyApplyment.setChannelVar1(ryxAccessResp.getResult().toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + String bizMsg = ryxAccessResp.getMsg(); + resultModifyApplyment.setApplyErrorInfo("[" + bizMsg + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + String remark = "瑞银信结算信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("瑞银信结算信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + throw new BizException("当前通道不支持该操作"); + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + resultModifyApplyment.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + MchApplyment mchApplyment = mchDataPair.getRight(); + + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject param = new JSONObject(); + String merInId = JSON.parseObject(mchApplyment.getSuccResParameter()).getString("merInId"); + param.put("merInId", merInId); + param.put("flag", "1"); + + RyxAccessResp ryxAccessResp = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_UPDATE_SETTLE_CARD, isvParams, param, null); + String bizMsg = ryxAccessResp.getMsg(); + String bizCode = ryxAccessResp.getCode(); + + if (!RyxpayKit.AUDIT_SUCCESS_CODE.equals(bizCode)) { + throw new BizException("查询变更结果失败, " + bizMsg); + } + + JSONObject merchBase = ryxAccessResp.getResult().getJSONObject("merchBase"); + String merStatus = merchBase.getString("merStatus"); + String reason = merchBase.getString("finalAuditNoMemo"); + + if (Objects.equals("00", merStatus)) { + // 审核通过 + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + localModifySettlement(mchDataPair); + } + + if (Objects.equals("32", merStatus)) { + // 修改失败 + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setRemark(reason); + mchModifyApplymentService.updateById(mchInfoConverter.toDbEntity(resultModifyApplyment)); + } + + return mchDataPair; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchWxConfigService.java new file mode 100644 index 0000000..37d8236 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayIsvmchWxConfigService.java @@ -0,0 +1,150 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.RyxAccessResp; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class RyxpayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + // 同步后子商户信息还是为空,则抛出异常 + if (StringUtils.isEmpty(mchApplyment.getChannelMchNo())) { + result.setErrInfo("随行付商户号为空"); + return result; + } + LambdaQueryChainWrapper wxSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + MchSubInfoEntity wx = wxSubInfoQuery.one(); + + if (wx == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + wx = wxSubInfoQuery.one(); + } + + if (wx == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if ("0".equals(wx.getStatus())) { + result.setChannelSubMchId(wx.getSubMchId()); + } else { + result.setState("未报备"); + result.setErrInfo("[" + wx.getRemark() + "]"); + return result; + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("merInId", JSON.parseObject(mchApplyment.getSuccResParameter()).getString("merInId")); + + // 发送请求 + RyxAccessResp response = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_QUERY, isvParams, bizContent, null); + String code = response.getCode(); + String msg = response.getMsg(); + if (!RyxpayKit.AUDIT_SUCCESS_CODE.equals(code)) { + + result.setState("04"); + result.setErrInfo(code + "[" + msg + "]"); + + return result; + } + + JSONObject wxCertificationInfo = response.getResult().getJSONObject("wxCertificationInfo"); + String wxAuthorizationStatusName = wxCertificationInfo.getString("wxAuthorizationStatusName"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + if ("已授权".equals(wxAuthorizationStatusName)) { + result.setState("已授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } else { + result.setState("未授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayKit.java new file mode 100644 index 0000000..011d326 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayKit.java @@ -0,0 +1,398 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SignUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.http.ContentType; +import cn.hutool.http.Header; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; + +import javax.xml.bind.DatatypeConverter; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 11:01 + */ +@Slf4j +public class RyxpayKit { + + public static final String AUDIT_SUCCESS_CODE = "0000"; + + /** + * 请求成功code + */ + public static final String SUCCESS_CODE = "000000"; + + /** + * 扩展成功状态码 + */ + public static final String EXT_SUCCESS_CODE = "200002"; + + /** + * 业务响应成功码 + */ + public static final String RESP_BIZ_SUCCESS = "S"; + + /** + * 业务响应失败码 + */ + public static final String RESP_BIZ_FAIL = "E"; + + /** + * 业务响应失败码 (不确定 处理中) + */ + public static final String RESP_BIZ_ING = "R"; + + public static final String IV_PARAM = "ivParam"; + public static final String AES_KEY = "aesKey"; + + public static RyxAccessModel accessCombineEncrypt(Map paramMap, RyxpayIsvParams isvParams) { + log.info("瑞银信-请求业务参数:{}", JSONObject.toJSONString(paramMap)); + RyxAccessModel ryxAccessModel = new RyxAccessModel(); + ryxAccessModel.setAccessId(isvParams.getAccessId()); + // 接入方订单号 + ryxAccessModel.setAccessMerchId(UUID.randomUUID().toString()); + // 发起请求的时间 + ryxAccessModel.setReqTime(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); + + // 保存AES密钥 + String ivParam = RandomUtil.randomString(16); + byte[] aesKey; + + RSA rsa = SecureUtil.rsa(isvParams.getPrivateKey(), isvParams.getPublicKey()); + Sign sign = SignUtil.sign(SignAlgorithm.SHA256withRSA, isvParams.getPrivateKey(), isvParams.getPublicKey()); + AES aes = new AES(Mode.CBC, Padding.PKCS5Padding); + aes.setIv(ivParam.getBytes(StandardCharsets.UTF_8)); + try { + aesKey = aes.getSecretKey().getEncoded(); + Map keyMap = new HashMap<>(); + // aesKey使用Base64编码 + keyMap.put(AES_KEY, Base64.encode(aesKey)); + keyMap.put(IV_PARAM, ivParam); + String encryptKey = rsa.encryptBase64(JSON.toJSONString(keyMap), KeyType.PublicKey); + ryxAccessModel.setEncryptKey(encryptKey); + } catch (Exception e) { + log.info("异常信息: ", e); + throw new BizException("瑞银信-AES密钥加密异常"); + } + + // 使用AES加密普通参数 + try { + String info = aes.encryptBase64(JSON.toJSONString(paramMap).getBytes(StandardCharsets.UTF_8)); + ryxAccessModel.setInfo(info); + } catch (Exception e) { + log.info("瑞银信-请求参数加密异常: ", e); + throw new BizException("瑞银信-请求参数加密异常"); + } + + // 参数加签 + Object[] sortedKeys = paramMap.keySet().toArray(); + Arrays.sort(sortedKeys); + + StringBuilder builder = new StringBuilder(); + builder.append("accessId=").append(ryxAccessModel.getAccessId()) + .append("&reqTime=").append(ryxAccessModel.getReqTime()) + .append("&ivParam=").append(ivParam); + for (Object key : sortedKeys) { + Object o = paramMap.get(key); + if (o != null) { + builder.append("&").append(key).append("=").append(o); + } + } + + log.info("签名原串:{}", builder); + // 客户端使用私钥签名 + try { + String signStr = cn.hutool.core.codec.Base64.encode(sign.sign(builder.toString())); + ryxAccessModel.setSign(signStr); + } catch (Exception e) { + log.info("瑞银信-签名异常: ", e); + throw new BizException("瑞银信-签名异常"); + } + + log.info("瑞银信-加密后的请求参数:{}", JSONObject.toJSONString(ryxAccessModel)); + + return ryxAccessModel; + } + + public static void main(String[] args) { + String respData = "{\"accessId\":\"000000000000038\",\"sign\":\"b653kuEY8GBQU983OAcPil0VOiOtK4mHtknhGujaCPdmrzhXkmfbn7LzERveU4XUjWqz8QyH24OMaSWuF2n2UuKPmKzFRD0ssJ6lWWKoo4c2mAv0nJ2WqD4M775J2zgQt4Wld4LxuAExpJDAVpKe5dcRsg9RTOOTjeqjBdfaPAO8kh3jvJxRHTXcAkPztl5CVYMWsd1u5NumVl12MvtKpWZl56frOe1ZzxuxuMGrlHnSJlNqsygpDk2b3zffOdLFHQV2d++ERfqV3K2oLUDAgwB38ehdYX2SFUeddY6BMNnWCEgKsDlciTJgtdlqTpMLliu8iYmSFfhCcIjzqCuLeg==\",\"reqTime\":\"20240307140757\",\"encryptKey\":\"u3SIim4XPuY6VEgj31ee4kQUf6R3oRaIAq7CGWLOWA8dk3zeuBwrSe803yah6YMm/bLJfKzslQuY0e3XjO/I9BKzVFtaiUjTfnkbHQouj7pe1Nauj3eWDu8d9qR4I9R+R04tdboXQRvRbGwt+cIkr+2MCMONr6Ut23CyDq9CED2ob4K6EjcmfbxeGQqP355EtqqbhcKwdlAJHWuz5w2un2pIG4biRKAQkcuIpA7Vxwh9YahrvGo3U+l6L9C8BX+xMmwNYFznOe79lJEHahR13b1csHEQrkraxtYQjbZpUm1d5/66tjG5BuT+TsqKJVJarXKrpeKzVu5P8zUxJsH24w==\",\"info\":\"EW1GNSpmAMX2uJQ9qpylV+iFjpr330XhNIlRSVOth8V+cjikqOvJ4GnZJ5EAbBy82gppCXIwrN4oP2h5Lpgb1Wyaw/xZiLA57ZCralZLUV589Y0HdvuUYH4WpZsvXsL6j+E3ZmoDZLiBY1XXqXDf2JfzacBTr2YE0aY4853432T1G297u2X5CGz59MIx9NR6fK51p8/i+9PwyPKOvKVLJQ==\"}"; + + RyxAccessModel ryxResult = JSON.parseObject(respData, RyxAccessModel.class); + + String isvParamStr = "{\"orgId\": \"OX000000002983\", \"wxUrl\": \"http://weixin.qq.com/q/02MRrq8qoreR2100000079\", \"aliUrl\": \"https://qr.alipay.com/0cb14483yoci65pbga3sif8\", \"accessId\": \"000000000000038\", \"settType\": [\"T1\", \"D1\"], \"publicKey\": \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiZTORAOR8d8aZB1Wg2IlRPySmozSey3gIdXNH5+YiUYBGTaUGCPuBXYGRu/iaD4HXYNhPm3+fNz33V/EbTKDppXz/8798u5oRLAr+ezqtKp4sCIVrdZhTY362NcUBDcRBpOMWLUplQVXcm6c36g/Cb3sC7eHZlZporWvihES1WWtIt8b46sWjhsn9gyw+ZIE+56INl5yheCgZQY4bz7nyPh5a/YpquXDZYuN40nxx80D7D4JGM1rWFdRskIm4UwyEguDD46i3QBumgb2KcYJBs1k1rQt561iZxJsYCofgPQZhBhLd4QBwEWsDkGeQjjeOVSj/naSZAsC4NBv4jc7ewIDAQAB\", \"cooperator\": \"ROX000000002983\", \"privateKey\": \"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDConKuuoKWDDpUDDW+aSlhxpoPHEIk3RKJG0PGNh/qlOfR8QYgGRyK4Ml1W3TgAvG+W50H3o2HK7k4Prr0nHSgvte/NgYbrTUo+M0eJyWyMkKY+A0PczeYtX0rmeWd1xjnR7BnXM/Rxj1NFP13+gkecBSnBmShH9T6CJnnD4rrJLG9PbCuq1CevXNSRklAMuufncW9uXeKT946cALDZwpNQKTHHLJUuxV4OjE1nCbSTk6HuLSf7pt3mooilEo9GoqGOOV4Zc/8TgpzCHBJnm81VatEytYcm/4FDcOzt/VJSQIYJWJJni07hmpXqIqG0TFGFsJaYqp84yznj1I73fmZAgMBAAECggEBAJ33Rmi1iyLIzdZFCqF9rE5k58h3wN82ZcLNVBZc+05iiDuGCNioSNgWVKthDNx6x0UeCbbHU8pvHCagExBQov+LpILWD+MKkuir9Z4RW7DixdZtC/yMIIVaVzq57vhKCTY8otlhJHI3GK2k6YskbZ48jSZ6M9Xphetga7hyjucENXNXa9OE+UJGhEzWF0hkD8GL1Umd2WO1AMgg2xIb2gpN5SF5zC9/3hj+iuexJBFJbvjbK6QB/OG3hEEkrAW+NEBcZEZHHUpw3xx9o8gEVTYnHKttgYMjBMZ+wqmGMaOOgmpps7jw3sj1E7KzMqARO/zn6eOd+NPZt8Q/WHMuTzkCgYEA/29N8mCtDVjUNjTFmrXWC8qSYDgGOV9L33YgDBsPwUM11R0k4vkU9C47ERKAWJKqh7u4UoUjct9loYHrCoOCif/8wjpTskMdmfTrwQU+oRVwPDQHC7WYpBoSgUZpZeuZDUxyr2BIqQ3oCKLkOou0bkQFxgGfBdfu75KYQoigCTcCgYEAwxCzv9SlSYEwMqewlF2MQwTgn/Q1lPd1IqMTcxOxn5Ws52eEIzZbqo82j7gWha/Ng1jWP5calkN1ZvROM6vgNKo7ia2AtbVZA74cYBOjTjQ+ZtyVBg0CNz9zYn++9KkCULfjLwixOSok96iziawamH1sHqBwam2N93BJnnpoO68CgYBgXwgTiDICNR9rjCF5q10kebscHkcK4k9n8dNJffRFwCvRSfuevscPEVorqMVPpZY9O6/hQmYLcwmPE8sv3koj8rbUONlXCkdizKsd2fK1J7d+n0qBOnRqhYOxznT5hRfrkoo6bKM9VQfUKlDdXdQnPfbHq9jphXyaWr6ja5SlpQKBgEs1QViQ8Dlq6d5d8SMC/nVIiCKj0ZTh4/O61GDmEvHoj4WYz8WTy7vzA6Jd47EfmyktM03JQKL212kegJhDiGpFyDbJAnsMtIlQ3zfb2nbohba7DWoL0fLjL+WmQ0WpdA8TFzCnNU1JBn/GN5K5HHf2w5z7Vtxx6O6iCIBlyZJZAoGAdEcgEdvR/fBKFN/rkMYXC2pbXPtXL1nnW7Nu39QyqjggLI6nwX310SmponwmPGgc6EMGuPGID8CpIfegpr+2YT9Ma2jHfHHNl/BkAdNx59aiQTcKOoE/7Z84ojMIqfDSHcbRy4y92XDfAVHrDHj503M8/CYpBhdjuuf38Y/W/0U=\", \"smzfPubKey\": \"MIIBIjA*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\", \"cooperatorPriKey\": \"MIIEvQI*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\"}"; + RyxpayIsvParams isvParams = JSON.parseObject(isvParamStr, RyxpayIsvParams.class); + + RyxAccessResp ryxAccessResp = accessResultDecrypt(ryxResult, RyxAccessResp.class, isvParams); + + } + + public static T accessResultDecrypt(RyxAccessModel ryxAccessModel, Class clazz, RyxpayIsvParams isvParams) { +// log.info("瑞银信-返回报文: \n{}", JSONObject.toJSONString(ryxAccessModel)); + + if (ryxAccessModel == null || ObjUtil.isEmpty(ryxAccessModel.getInfo())) { + throw new BizException("请求异常"); + } + + String info = ryxAccessModel.getInfo(); + String encryptKey = ryxAccessModel.getEncryptKey(); + String signStr = ryxAccessModel.getSign(); + String reqTime = ryxAccessModel.getReqTime(); + + Map aesKeyMap; + + RSA rsa = SecureUtil.rsa(isvParams.getPrivateKey(), isvParams.getPublicKey()); + try { + // 使用客户端RSA密钥解密 AES密钥 + String aesKeyInfo = rsa.decryptStr(encryptKey, KeyType.PrivateKey); + aesKeyMap = JSON.parseObject(aesKeyInfo); + } catch (Exception e) { + log.info("瑞银信-请求结果密钥解密异常", e); + throw new BizException("瑞银信-请求结果密钥解密异常"); + } + + Assert.notNull(aesKeyMap, "瑞银信-请求结果密钥解密异常"); + // AES解密服务器返回的数据 + String data; + String ivParam; + try { + byte[] bytesInfo = Base64.decode(info); + byte[] key = Base64.decode(aesKeyMap.get(AES_KEY).toString()); + ivParam = aesKeyMap.get(IV_PARAM).toString(); + AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key); + aes.setIv(ivParam.getBytes(StandardCharsets.UTF_8)); + + byte[] decryptData = aes.decrypt(bytesInfo); + data = new String(decryptData, StandardCharsets.UTF_8); + } catch (Exception e) { + log.info("瑞银信-请求结果密钥解密异常", e); + throw new BizException("瑞银信-请求结果密钥解密异常"); + } + + log.info("瑞银信-返回报文解密:\n{}", data); + + T result = JSON.parseObject(data, clazz); + + StringBuilder builder = new StringBuilder(); + builder.append("accessId=").append(ryxAccessModel.getAccessId()).append("&reqTime=").append(reqTime) + .append("&ivParam=").append(ivParam).append("&result=").append(data); + + try { + Sign sign = SignUtil.sign(SignAlgorithm.SHA256withRSA, isvParams.getPrivateKey(), isvParams.getPublicKey()); + boolean verify = sign.verify(builder.toString().getBytes(StandardCharsets.UTF_8), signStr.getBytes(StandardCharsets.UTF_8)); + log.debug(verify ? "验签成功":"验签失败"); + } catch (Exception e) { + log.info("瑞银信-返回报文验签异常", e); + } + + return result; + } + + /** + * + * @param otherParam 主要指文件 + * @return + */ + public static RyxAccessResp auditReqApi(ReqMethod.Method method, RyxpayIsvParams isvParams, JSONObject reqData, JSONObject otherParam) { + String url = ReqMethod.getUrl(method); + log.info("瑞银信-请求链接: {}", url); + + HttpRequest form = HttpRequest.post(url); + + // 组装加密请求参数 + if (reqData != null) { + RyxAccessModel ryxAccessModel = accessCombineEncrypt(reqData, isvParams); + + form.form("accessId", ryxAccessModel.getAccessId()) + .form("reqTime", ryxAccessModel.getReqTime()) + .form("info", ryxAccessModel.getInfo()) + .form("sign", ryxAccessModel.getSign()) + .form("encryptKey", ryxAccessModel.getEncryptKey()); + + if (method == ReqMethod.Method.MERCHANT_INCOME) { + form.form("accessMerchId", ryxAccessModel.getAccessMerchId()); + } + + if (otherParam != null && !otherParam.isEmpty()) { + form.header(Header.CONTENT_TYPE.getValue(), ContentType.MULTIPART.getValue()); + + otherParam.forEach((key, value) -> { + if (value instanceof List) { + ((List) value).forEach(item -> { + form.form(key, item); + }); + } else { + form.form(key, value); + } + }); + + } else { + form.header(Header.CONTENT_TYPE.getValue(), ContentType.FORM_URLENCODED.getValue()); + } + } + + // 发起请求 + HttpResponse execute = form.execute(); + String body = execute.body(); + log.info("瑞银信进件请求返回参数为{}", body); + if (!execute.isOk()) { + log.info("瑞银信进件请求失败, 返回参数为{}", body); + throw new BizException("瑞银信接口请求异常"); + } + + RyxAccessModel ryxResult = JSON.parseObject(body, RyxAccessModel.class); + // 返回参数校验 + Assert.notNull(ryxResult, "未知请求结果"); + + return accessResultDecrypt(ryxResult, RyxAccessResp.class, isvParams); + } + + + /** + * 支付请求 + * @param serviceCode + * @param isvParams + * @param reqData + * @return + */ + public static PayRespEntity payReqApi(ReqMethod.ServiceCode serviceCode, RyxpayIsvParams isvParams, JSONObject reqData,String msgId,String notifyUrl){ + PayBizEntity bizEntity = new PayBizEntity(reqData,msgId); + PayReqEntity reqEntity = payParamsEncrypt(bizEntity,isvParams, serviceCode.getValue(),notifyUrl); + HttpResponse response = HttpRequest.post(ReqMethod.getUrl(serviceCode.getMethod())).form(reqEntity.toMap()).execute(); + log.info("【瑞银信】响应参数:{}", response.body()); + PayRespEntity result = resultParamsDecode(response.body(),isvParams); + String respCode = result.getRespCode(); + if(!SUCCESS_CODE.equals(respCode) && !EXT_SUCCESS_CODE.equals(respCode)){ + throw new BizException(result.getRespMsg()); + } + String respType = result.getRespType(); + if(RyxpayKit.RESP_BIZ_FAIL.equals(respType)){ + throw new BizException(result.getRespMsg()); + } + return result; + } + + /** + * 解析返回参数 + * @param response + * @return + */ + public static PayRespEntity resultParamsDecode(Object response, RyxpayIsvParams isvParams) { + JSONObject resp = null; + if(response instanceof String ){ + resp = JSONObject.parseObject((String) response); + }else if(response instanceof JSONObject ){ + resp = (JSONObject)response; + } + if(resp.containsKey("respCode") && RESP_BIZ_FAIL.equals(resp.getString("respType"))){ + throw new BizException(resp.getString("respMsg")); + } + String resEncryptData = resp.getString("encryptData"); + String resEncryptKey = resp.getString("encryptKey"); + try { + byte[] keyBytes = Base64.decode(resEncryptKey.getBytes(StandardCharsets.UTF_8)); + RSA rsa = SecureUtil.rsa(isvParams.getCooperatorPriKey(),null); + byte[] merchantAESKeyBytes = rsa.decrypt(keyBytes, KeyType.PrivateKey); + byte[] dataBytes = Base64.decode(resEncryptData.getBytes(StandardCharsets.UTF_8)); + AES aes = new AES(Mode.ECB, Padding.PKCS5Padding, merchantAESKeyBytes); + String resXml = aes.decryptStr(dataBytes); + log.info("【瑞银信】返回参数解析结果:{}",resXml); + return JSONObject.parseObject(resXml,PayRespEntity.class); + } catch (Exception e) { + throw new BizException("【瑞银信】返回参数解析异常"); + } + } + + private static PayReqEntity payParamsEncrypt(PayBizEntity bizEntity,RyxpayIsvParams isvParams, String tranCode,String notifyUrl) { + String bizData = JSON.toJSONString(bizEntity); + log.info("【瑞银信支付】请求加密前:{}",bizData); + PayReqEntity request = new PayReqEntity(); + request.setCooperator(isvParams.getCooperator()); + try { + byte[] plainBytes = bizData.getBytes(StandardCharsets.UTF_8); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA1withRSA, isvParams.getCooperatorPriKey(), isvParams.getSmzfPubKey()); + String key = RandomUtil.randomString(16); + byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8); + AES aes = new AES(Mode.ECB, Padding.PKCS5Padding, keyBytes); + String encryptData = aes.encryptBase64(plainBytes); + String signData = DatatypeConverter.printBase64Binary(sign.sign(bizData)); + RSA rsa = SecureUtil.rsa(null, isvParams.getSmzfPubKey()); + String encrtptKey = DatatypeConverter.printBase64Binary(rsa.encrypt(key, KeyType.PublicKey)); + request.setEncryptData(encryptData); + request.setSignData(signData); + request.setEncrtptKey(encrtptKey); + request.setTranCode(tranCode); + request.setCallBack(notifyUrl); + request.setReqMsgId(bizEntity.getSmzfMsgId()); + } catch (Exception e) { + e.printStackTrace(); + } + log.info("【瑞银信支付】请求加密后:{}",JSON.toJSONString(request)); + return request; + } + + /** + * 设置通用支付参数 + * @param mchAppConfigContext + * @param bizContent + * @param payOrder + */ + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent, PayOrder payOrder, UnifiedOrderRQ rq) { + bizContent.put("merchantCode", mchAppConfigContext.getMchApplyment().getChannelMchNo()); + switch (payOrder.getWayCodeType()){ + case CS.PAY_WAY_CODE_TYPE.ALIPAY: + bizContent.put("payWay", "ZFBZF"); + if(rq.getHbFqNum() != null){ + JSONObject extendParams = new JSONObject(); + extendParams.put("hb_fq_num",rq.getHbFqNum()); + extendParams.put("hb_fq_seller_percent",rq.getHbFqPercent()); + bizContent.put("extendParams",extendParams); + } + break; + case CS.PAY_WAY_CODE_TYPE.WECHAT: + bizContent.put("payWay", "WXZF"); + break; + case CS.PAY_WAY_CODE_TYPE.UNIONPAY: + bizContent.put("payWay", "UPZF"); + break; + default: + throw new BizException("暂不支持当前支付方式,请更换"); + } + //支付场景,条码支付-1 声波支付-2 + bizContent.put("scene", "1"); + bizContent.put("totalAmount",AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + bizContent.put("subject",payOrder.getSubject()); + bizContent.put("desc",payOrder.getBuyerRemark()); + Integer limitPay = rq.getLimitPay(); + if(limitPay == null){ + bizContent.put("limitPay",limitPay); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApiService.java new file mode 100644 index 0000000..c7c2583 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApiService.java @@ -0,0 +1,178 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +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.ruipay.RyxpayIsvParams; +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 com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.RyxAccessResp; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO + * 瑞银信商户api服务类 + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class RyxpayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * 新增appid或者支付授权目录 + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + ReqMethod.ServiceCode method = ReqMethod.ServiceCode.SUB_APPID; + JSONObject bizData = new JSONObject(); + bizData.put("merchantCode",applyment.getChannelMchNo()); + if(ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())){ + bizData.put("jsapiPath",mchRq.getJsapiPath()); + method = ReqMethod.ServiceCode.JSAPI_PATH; + }else{ + bizData.put("subAppid",mchRq.getAppid()); + } + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(applyment); + PayRespEntity response = RyxpayKit.payReqApi(method, isvParams, bizData, null, null); + ChannelRetMsg retMsg = new ChannelRetMsg(); + retMsg.setChannelBizData(response.getData()); + String respType = response.getRespType(); + retMsg.setChannelErrCode(response.getRespCode()); + retMsg.setChannelErrMsg(response.getRespMsg()); + if(RyxpayKit.RESP_BIZ_SUCCESS.equals(respType)){ + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return retMsg; + } + + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, RyxpayIsvParams isvParams) { + ReqMethod.Method method = ReqMethod.Method.MERCHANT_TODAY_SETTLE_QUERY; + JSONObject bizData = new JSONObject(); + bizData.put("s_merInId",settleRq.getExtMchNo()); + if(StringUtils.isNotEmpty(settleRq.getTransDateScope())){ + method = ReqMethod.Method.MERCHANT_SETTLE_QUERY; + String[] transDateScope = settleRq.getTransDateScope().split(SettleInfo.TRANS_SCOPE_DATE_SPLIT); + bizData.put("s_tranDates",DateUtil.format(DateUtil.parse(transDateScope[0],DatePattern.NORM_DATE_PATTERN),DatePattern.PURE_DATE_PATTERN)); + bizData.put("s_tranDatee",DateUtil.format(DateUtil.parse(transDateScope[1],DatePattern.NORM_DATE_PATTERN),DatePattern.PURE_DATE_PATTERN)); + bizData.put("page",settleRq.getPage()); + bizData.put("rows",settleRq.getSize()); + } + RyxAccessResp ryxAccessResp = RyxpayKit.auditReqApi(method, isvParams, bizData, null); + JSONObject resultData = ryxAccessResp.getResult(); + JSONArray infos = resultData.getJSONArray("list"); + if(infos == null || infos.isEmpty()){ + return null; + } + List result = new ArrayList<>(infos.size()); + infos.forEach(item -> { + JSONObject itemData = ((JSONObject) item); + JSONObject data = new JSONObject(); + //没有结算编号 根据参数生成一个编号 + data.put("billNo",itemData.getString("merId") + "_" + itemData.getString("settleType") + "_" + itemData.getString("settDate")); + data.put("isvNo", isvNo); + data.put("accountNo",itemData.getString("cardNo")); + data.put("accountName",itemData.getString("cardName")); + if(StringUtils.isNotBlank(itemData.getString("amt"))){ + long stlAmt = itemData.getBigDecimal("amt").multiply(BigDecimal.valueOf(100)).longValue(); + data.put("settleAmt",stlAmt); + } + SettleState payState = SettleState.getVal(itemData.getString("status")); + switch (payState){ + case SUCCESS: + data.put("state", SettleInfo.SUCCESS); + break; + case PROGRESS: + data.put("state", SettleInfo.PROGRESS); + break; + case FAIL: + data.put("state", SettleInfo.FAIL); + break; + default: + data.put("state", SettleInfo.WAIT); + break; + } + data.put("channelState",payState.getState()); + data.put("channelCode",itemData.getString("retrunCode")); + data.put("remark",itemData.getString("failReason")); + data.put("bankName",itemData.getString("bankName")); + String settDate = itemData.getString("settDate"); + if(StringUtils.isNotBlank(settDate)){ + DateTime settleTime = DateUtil.parse(settDate, DatePattern.PURE_DATETIME_PATTERN); + data.put("settleDate",DateUtil.format(settleTime,DatePattern.NORM_DATE_PATTERN)); + data.put("settleTime",settleTime); + } + data.put("extra", itemData.toString()); + result.add(data); + }); + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState{ + + SUCCESS("出款成功","结算成功"), + + PROGRESS("出款中","付款中"), + + FAIL("出款失败","付款失败"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state){ + SettleState[] values = values(); + for (SettleState val:values) { + if(val.getState().equals(state)){ + return val; + } + } + return PROGRESS; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApplymentService.java new file mode 100644 index 0000000..7e17d90 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayMchApplymentService.java @@ -0,0 +1,361 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.resource.BytesResource; +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.RyxpayApplymentInfo; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.RyxAccessResp; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Service("ryxpayMchApplymentService") +public class RyxpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private SysConfigService sysConfigService; + + public byte[] getFileBytes(String imgUrl, String picType) { + Assert.notNull(imgUrl, "缺少类型为" + picType + "的图片"); + + // 下载文件 + byte[] imgFileByteArray = null; + try { + ByteArrayOutputStream baos = ImageUtils.compressNetPic(imgUrl, 2048 * 1024); + imgFileByteArray = baos.toByteArray(); + } catch (IORuntimeException e) { + e.printStackTrace(); + } + + return imgFileByteArray; + } + + public JSONObject getApplymentParams(MchApplyment mchApplyment) { + JSONObject result = new JSONObject(); + List files = new ArrayList<>(); + result.put("files", files); + RyxpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), RyxpayApplymentInfo.class); + + RyxpayIsvParams isvParams = ((RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + result.put("accessMode", "1"); + result.put("orgId", isvParams.getOrgId()); + result.put("merProp", applymentInfo.getMerProp()); + + files.add(new BytesResource(getFileBytes(applymentInfo.getStoreOuterImg(), "门头照"), "pic0211.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getStoreInnerImg(), "门店内景照"), "pic0117.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getStoreCashierImg(), "收银台照"), "pic0217.jpg")); + + if (!"7".equals(result.getString("merProp"))) { + result.put("merName", applymentInfo.getMerName()); + result.put("orgMerName", applymentInfo.getOrgMerName()); + + } + + result.put("merNameAbbr", applymentInfo.getMerNameAbbr()); + result.put("merchRelp", ObjUtil.defaultIfNull(applymentInfo.getMerchRelp(), "00")); + + if (!"7".equals(result.getString("merProp"))) { + files.add(new BytesResource(getFileBytes(applymentInfo.getLicenseImg(), "营业执照"), "pic0103.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getIdcard1Img(), "法人身份证人像面"), "pic0111.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getIdcard2Img(), "法人身份证国徽面"), "pic0112.jpg")); + result.put("licType", "1"); + result.put("licNum", applymentInfo.getLicNum()); + result.put("licNumStartTime", applymentInfo.getLicNumStartTime()); + result.put("licNumTime", applymentInfo.getLicNumTime()); + result.put("credPeople", applymentInfo.getCredPeople()); + result.put("credType", applymentInfo.getCredType()); + result.put("credNo", applymentInfo.getCredNo()); + result.put("credStartTime", applymentInfo.getCredStartTime()); + result.put("credTime", applymentInfo.getCredTime()); + result.put("credAddr", applymentInfo.getIdcardAddress()); + + if ("Y".equals(applymentInfo.getAuthSettle())) { + files.add(new BytesResource(getFileBytes(applymentInfo.getSettAccountIdcard1Img(), "结算人身份证人像面"), "pic0119.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getSettAccountIdcard2Img(), "结算人身份证国徽面"), "pic0120.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getLetterOfAuthPic(), "非法人结算授权函"), "pic0205.jpg")); + } + } else { + result.put("microBizType", applymentInfo.getMicroBizType()); + + // 小微 + files.add(new BytesResource(getFileBytes(applymentInfo.getStoreInnerImg(), "门店内景照"), "pic0118.jpg")); + + files.add(new BytesResource(getFileBytes(applymentInfo.getIdcard1Img(), "经营者身份证人像面"), "pic0119.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getIdcard2Img(), "经营者身份证国徽面"), "pic0120.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getIdcardInHandImg(), "经营者手持身份证照"), "pic0105.jpg")); + } + + if ("3".equals(applymentInfo.getSettleType())) { + // 对公 + files.add(new BytesResource(getFileBytes(applymentInfo.getSettAccountLicenseImg(), "开户许可证"), "pic0109.jpg")); + } else { + files.add(new BytesResource(getFileBytes(applymentInfo.getSettAccountLicenseImg(), "银行卡卡号面"), "pic0206.jpg")); + } + + result.put("cityArea", applymentInfo.getCityArea()); + result.put("longitude", applymentInfo.getLongitude()); + result.put("latitude", applymentInfo.getLatitude()); + result.put("operateProvince", applymentInfo.getOperateProvince()); + result.put("operateCity", applymentInfo.getOperateCity()); + result.put("operateArea", applymentInfo.getOperateArea()); + result.put("contactPerson", applymentInfo.getContactPerson()); + result.put("contactPhone", applymentInfo.getContactPhone()); + result.put("operateAddr", applymentInfo.getOperateAddr()); + result.put("regAddr", applymentInfo.getRegAddr()); + result.put("manaScop", applymentInfo.getManaScop()); + result.put("mcc", applymentInfo.getMcc()); + + result.put("bankCard", applymentInfo.getBankCard()); + result.put("accountProp", applymentInfo.getAccountProp()); + result.put("settleType", applymentInfo.getSettleType()); + result.put("bankCardName", applymentInfo.getBankCardName()); + result.put("settleCredType", applymentInfo.getSettleCredType()); + result.put("settleCredNo", applymentInfo.getSettleCredNo()); + result.put("settleCredStartTime", applymentInfo.getSettleCredStartTime()); + result.put("settleCredTime", applymentInfo.getSettleCredTime()); + result.put("bankCityArea", applymentInfo.getBankCityArea()); + result.put("headBankNo", applymentInfo.getHeadBankNo()); +// result.put("openBankName", applymentInfo.getOpenBankName()); + result.put("openBankChild", applymentInfo.getOpenBankChild()); + + result.put("modelType", "2"); + result.put("debitRate", "2"); + result.put("pactType", "1"); + + applymentInfo.collRateInfo(result); + result.put("termNum", "1"); + result.put("serviceType", applymentInfo.getServiceType()); + result.put("tradeTypeReimburse", ObjUtil.defaultIfNull(applymentInfo.getTradeTypeReimburse(), "0")); + result.put("certificationType", ObjUtil.defaultIfNull(applymentInfo.getCertificationType(), "1")); + result.put("alipayCertificationType", ObjUtil.defaultIfNull(applymentInfo.getAlipayCertificationType(), "1")); + result.put("regAddress", applymentInfo.getOperateAddr()); + result.put("contactSameToLegal", applymentInfo.getContactSameToLegal()); + result.put("contactCredType", ObjUtil.defaultIfNull(applymentInfo.getContactCredType(), "0105")); + result.put("contactStartTime", applymentInfo.getContactStartTime()); + result.put("contactTime", applymentInfo.getContactTime()); + result.put("contactPersonCred", applymentInfo.getContactPersonCred()); + files.add(new BytesResource(getFileBytes(applymentInfo.getContactCardImg1(), "联系人身份证卡号面"), "pic0311.jpg")); + files.add(new BytesResource(getFileBytes(applymentInfo.getContactCardImg2(), "联系人身份证国徽面"), "pic0312.jpg")); + result.put("ifbenefit", "0"); + + // 微信配置 + WxpayOauth2Params wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchApplyment.getIsvNo(), CS.IF_CODE.WXPAY); + if (wxpayOauth2Params == null) { + throw new BizException("服务商未配置微信oauth信息"); + } + String paySiteUrl = sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + String subAppId = ""; + if (!ObjUtil.isEmpty(wxpayOauth2Params.getAppId())) { + subAppId = wxpayOauth2Params.getAppId(); + } + + if (!ObjUtil.isEmpty(wxpayOauth2Params.getLiteAppId())) { + subAppId = subAppId + "," + wxpayOauth2Params.getLiteAppId(); + } + + if (ObjUtil.isEmpty(subAppId)) { + throw new BizException("服务商未配置微信oauth信息"); + } + + result.put("subAppid", subAppId); + result.put("jsapiPath", paySiteUrl + "/"); + + return result; + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + String logPrefix = "【瑞银信商户进件状态查询】"; + MchApplyment result = new MchApplyment(); + result.setState(mchApplyment.getState()); + result.setApplyId(mchApplyment.getApplyId()); + + if (mchApplyment.getState() == MchApplyment.STATE_AUDITING + || mchApplyment.getState() == MchApplyment.STATE_WAIT_SIGN) { + // 资料确认状态查询 + // 获取支付参数 + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContent.put("orderId", mchApplyment.getChannelApplyNo()); + + // 解密后数据 + RyxAccessResp resData = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_INCOME_RESULT, isvParams, bizContent, null); + + String bizMsg = resData.getMsg(); + String bizCode = resData.getCode(); + + if (!RyxpayKit.AUDIT_SUCCESS_CODE.equals(bizCode)) { + result.setApplyErrorInfo(bizCode + "[" + bizMsg + "]"); + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchApplyment.setChannelVar1(resData.getResult().toJSONString()); + return mchApplyment; + } + + String taskStatus = resData.getResult().getString("status"); + String suggestion = resData.getResult().getString("memo"); + + String onlMerId = resData.getResult().getString("onlMerId"); + result.setSuccResParameter(resData.getResult().toJSONString()); + result.setApplyErrorInfo(bizCode + "[" + suggestion + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, bizCode, suggestion); + + + // 审核成功 + if ("3".equals(taskStatus)) { + result.setChannelMchNo(onlMerId); + result.setState(MchApplyment.STATE_SUCCESS); + result.setChannelVar1(resData.getResult().toString()); + subMchColl(result, resData.getResult()); + } + // 待签约 + else if ("5".equals(taskStatus)) { + String merInId = resData.getResult().getString("merInId"); + + // 待签约 + RyxpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), RyxpayApplymentInfo.class); + + String merName; + if (MchApplyment.MERCHANT_TYPE_PERSONAL == mchApplyment.getMerchantType()) { + merName = "商户" + applymentInfo.getIdcardName(); + } else { + merName = applymentInfo.getMchFullName(); + } + + try { + merName = URLEncoder.encode(merName, "UTF-8"); + } catch (UnsupportedEncodingException ignored) { + } + + String urlTemplate = "https://rjp.ruiyinxin.com/mims2/ruijiaSign/index.html?merInId=%s&merName=%s"; + String url = String.format(urlTemplate, merInId, merName); + JSONObject channelVar2 = new JSONObject(); + channelVar2.put("signUrl", url); + result.setChannelVar2(channelVar2.toJSONString()); + result.setState(MchApplyment.STATE_WAIT_SIGN); + return result; + } else if ("1".equals(taskStatus)) { + // 审核中 + } else { + result.setApplyErrorInfo("[" + suggestion + "]"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return result; + } + } + + return result; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public void subMchColl(MchApplyment mchApplyment, Object callback) { + JSONObject auditResult = (JSONObject) callback; + if (auditResult.getString("wxMerId") != null) { + try { + // 保存微信子商户信息 + MchSubInfoEntity mchSubInfo = new MchSubInfoEntity(); + mchSubInfo.setChannelMchNo(mchApplyment.getChannelMchNo()); + mchSubInfo.setMchApplyId(mchApplyment.getApplyId()); + mchSubInfo.setSubMchType("WX"); + mchSubInfo.setStatus(auditResult.getString("wxStatus")); + mchSubInfo.setMainUse(1); + mchSubInfo.setRemark(auditResult.getString("wxResult")); + mchSubInfo.setSubMchId(auditResult.getString("wxMerId")); + mchSubInfo.setSubMchWay("RYX"); + mchSubInfo.setExt(auditResult); + mchSubInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + mchSubInfoService.save(mchSubInfo); + } catch (DuplicateKeyException e) { + log.warn("相同的微信子商户号, 不需要重复保存"); + } catch (Exception e) { + e.printStackTrace(); + log.warn("保存微信子商户号错误"); + } + } + + if (auditResult.getString("zfbMerId") != null) { + try { + // 保存支付宝子商户信息 + MchSubInfoEntity mchSubInfo = new MchSubInfoEntity(); + mchSubInfo.setChannelMchNo(mchApplyment.getChannelMchNo()); + mchSubInfo.setMchApplyId(mchApplyment.getApplyId()); + mchSubInfo.setSubMchType("ZFB"); + mchSubInfo.setStatus(auditResult.getString("zfbStatus")); + mchSubInfo.setMainUse(1); + mchSubInfo.setRemark(auditResult.getString("zfbResult")); + mchSubInfo.setSubMchId(auditResult.getString("zfbMerId")); + mchSubInfo.setSubMchWay("RYX"); + mchSubInfo.setExt(auditResult); + mchSubInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + mchSubInfoService.save(mchSubInfo); + } catch (DuplicateKeyException e) { + log.warn("相同的支付宝子商户号, 不需要重复保存"); + } catch (Exception e) { + e.printStackTrace(); + log.warn("保存支付宝子商户号错误"); + } + } + } + + @Override + public void subMchColl(MchApplyment mchApplyment) { + RyxpayIsvParams ryxpayIsvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject param = new JSONObject(); + param.put("orderId", mchApplyment.getChannelApplyNo()); + + RyxAccessResp ryxAccessResp = RyxpayKit.auditReqApi(ReqMethod.Method.MERCHANT_INCOME_RESULT, ryxpayIsvParams, param, null); + + if (!RyxpayKit.AUDIT_SUCCESS_CODE.equals(ryxAccessResp.getCode())) { + throw new BizException("瑞银信查询商户进件结果失败, " + ryxAccessResp.getMsg()); + } + + subMchColl(mchApplyment, ryxAccessResp.getResult()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderCloseService.java new file mode 100644 index 0000000..be4dfaa --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderCloseService.java @@ -0,0 +1,47 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 关闭订单接口实现类 + * + * @author xiaoyu + * + * @date 2022/5/16 9:09 + */ +@Slf4j +@Service +public class RyxpayPayOrderCloseService implements IPayOrderCloseService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + try { + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),payOrder.getIfCode()); + JSONObject bizContent = new JSONObject(); + bizContent.put("merchantCode", payOrder.getChannelMchNo()); + bizContent.put("oriReqMsgId", payOrder.getPayOrderId()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF015,isvParams ,bizContent, payOrder.getPayOrderId(), null); + String respType = response.getRespType(); + if (!RyxpayKit.RESP_BIZ_SUCCESS.equals(respType)) { + return ChannelRetMsg.confirmFail(response.getSmzfMsgId(),response.getRespCode(),response.getRespMsg()); + } + return ChannelRetMsg.confirmSuccess(response.getSmzfMsgId()); + }catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderQueryService.java new file mode 100644 index 0000000..e93a0e2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPayOrderQueryService.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 查询订单 瑞银信 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class RyxpayPayOrderQueryService implements IPayOrderQueryService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + try { + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),payOrder.getIfCode()); + JSONObject bizContent = new JSONObject(); + bizContent.put("merchantCode", payOrder.getChannelMchNo()); + bizContent.put("oriReqDate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + bizContent.put("oriReqMsgId",payOrder.getPayOrderId()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF006, isvParams, bizContent, null, null); + JSONObject bizData = response.getData(); + String oriRespType = bizData.getString("oriRespType"); + if(RyxpayKit.RESP_BIZ_ING.equals(oriRespType)){ + return ChannelRetMsg.waiting(); + }else if(RyxpayKit.RESP_BIZ_FAIL.equals(oriRespType)){ + return ChannelRetMsg.confirmFail(response.getData().getString("oriRespCode"),response.getData().getString("oriRespMsg")); + }else if(RyxpayKit.RESP_BIZ_SUCCESS.equals(oriRespType)){ + String payType = response.getData().getString("payType"); + String drType = CS.DrType.OTHER.getType(); + if(StringUtils.isNotEmpty(payType)){ + switch (payType){ + case "1": + drType = CS.DrType.DEBIT.getType(); + break; + case "2": + drType = CS.DrType.DEBIT.getType(); + break; + } + } + return ChannelRetMsg.confirmSuccess(response.getSmzfMsgId(),response.getData().getString("channelTradeNo") ,response.getChannelMsgId(),drType); + } + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPaymentService.java new file mode 100644 index 0000000..181574d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayPaymentService.java @@ -0,0 +1,153 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.applyment.RyxpayApplymentInfo; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.db.entity.RegionCodePayRyx; +import com.jeequan.jeepay.service.impl.RegionCodePayRyxService; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import java.util.Arrays; + +/** + * 瑞银信支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Slf4j +@Service +public class RyxpayPaymentService extends AbstractPaymentService { + + @Autowired + private RegionCodePayRyxService regionCodePayRyxService; + + /** + * 瑞银信花呗分期参数支持选项 + */ + public static final int[] ALI_HB_FQ_NUM_ARR = {3,6,12}; + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + public void preCheckAli(UnifiedOrderRQ rq) { + Integer hbFqNum = rq.getHbFqNum(); + if(hbFqNum != null){ + boolean isCheck = Arrays.stream(ALI_HB_FQ_NUM_ARR).anyMatch(num -> num == hbFqNum); + if(!isCheck){ + throw new BizException("支付宝支付花呗分期参数有误,仅可支持数值为"+ StringUtils.join(ALI_HB_FQ_NUM_ARR,",") +"期"); + } + Integer hbFqPercent = rq.getHbFqPercent(); + if(hbFqPercent != null && hbFqPercent != 0){ + throw new BizException("花呗分期商家承担手续费比例目前只支持用户承担手续费"); + } + rq.setHbFqPercent(0); + } + } + + /** + * 通用返回参数处理 + * @param response + * @param res + * @param wayCodeType + */ + public void initCommonResult(PayRespEntity response, ChannelRetMsg res,String wayCodeType) { + res.setChannelState(ChannelRetMsg.ChannelState.WAITING); + res.setNeedQuery(true); + res.setChannelBizData(response.getData()); + res.setChannelErrCode(response.getRespCode()); + res.setChannelErrMsg(response.getRespMsg()); + String respType = response.getRespType(); + if(RyxpayKit.RESP_BIZ_FAIL.equals(respType)){ + res.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + res.setNeedQuery(false); + }else{ + JSONObject bizData = response.getData(); + String smzfMsgId = response.getSmzfMsgId(); + String channelMsgId = response.getChannelMsgId(); + String buyerId = bizData.getString("buyerId"); + String channelTradeNo = bizData.getString("channelTradeNo"); + String payType = bizData.getString("payType"); + if(StringUtils.isNotEmpty(payType)){ + switch (payType){ + case "1": + res.setDrType(CS.DrType.DEBIT.getType()); + break; + case "2": + res.setDrType(CS.DrType.CREDIT.getType()); + break; + default: + res.setDrType(CS.DrType.OTHER.getType()); + break; + } + }else{ + res.setDrType(CS.DrType.OTHER.getType()); + } + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + res.setChannelUserId(buyerId); + res.setChannelOrderId(smzfMsgId); + res.setPlatformMchOrderNo(channelMsgId); + res.setPlatformOrderNo(channelTradeNo); + if(StringUtils.isNotEmpty(channelTradeNo)){ + channelTradeNo = channelTradeNo.substring(2); + jsapiMsg.setTradeNo(channelTradeNo); + } + String wxjsapiStr = bizData.getString("wxjsapiStr"); + if(StringUtils.isNotEmpty(wxjsapiStr)){ + jsapiMsg = JSON.parseObject(wxjsapiStr,ChannelJsapiMsg.class); + } + jsapiMsg.setRedirectUrl(bizData.getString("redirectUrl")); + res.setJsapiMsg(jsapiMsg); + } + } + + /** + * 加载商户扩展信息 + * @param bizData + * @param mchAppConfigContext + */ + public void loadMchExtInfo(JSONObject bizData,MchAppConfigContext mchAppConfigContext){ + MchApplyment mchApplyment = mchAppConfigContext.getMchApplyment(); + RyxpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), RyxpayApplymentInfo.class); + JSONArray areaName = applymentInfo.getAreaName(); + RegionCodePayRyx byAreaName = regionCodePayRyxService.getByAreaName(areaName.getString(0), areaName.getString(1), areaName.getString(2)); + Assert.notNull(byAreaName, "获取瑞银信地区信息异常"); + bizData.put("areaInfo",byAreaName.getAreaCode()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayRefundService.java new file mode 100644 index 0000000..57b8f78 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/RyxpayRefundService.java @@ -0,0 +1,118 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvsubMchParams; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 瑞银信 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class RyxpayRefundService extends AbstractRefundService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.RYXPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + /** + * 退款 + * @param bizRQ + * @param refundOrder + * @param payOrder + * @param mchAppConfigContext + * @return + * @throws Exception + */ + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),payOrder.getIfCode()); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + bizContent.put("merchantCode",payOrder.getChannelMchNo()); + bizContent.put("oriReqDate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + bizContent.put("oriReqMsgId",payOrder.getPayOrderId()); + bizContent.put("refundAmount", AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount())); + bizContent.put("refundReason",refundOrder.getRefundReason()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF004, isvParams, bizContent, refundOrder.getRefundOrderId(), getNotifyUrl()); + channelRetMsg.setChannelBizData(response.getData()); + channelRetMsg.setChannelOrderId(response.getSmzfMsgId()); + channelRetMsg.setChannelErrCode(response.getRespCode()); + channelRetMsg.setChannelErrMsg(response.getRespMsg()); + channelRetMsg.setPlatformMchOrderNo(response.getChannelMsgId()); + String respType = response.getRespType(); + if(RyxpayKit.RESP_BIZ_SUCCESS.equals(respType)){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else if(RyxpayKit.RESP_BIZ_FAIL.equals(respType)){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),refundOrder.getIfCode()); + RyxpayIsvsubMchParams mchParams = (RyxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getMchApplyment().getAutoConfigMchAppId(), refundOrder.getIfCode()); + JSONObject bizContent = new JSONObject(); + bizContent.put("merchantCode",mchParams.getMerchantCode()); + bizContent.put("oriReqDate",mchParams.getMerchantCode()); + bizContent.put("oriReqMsgId",refundOrder.getRefundOrderId()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF006, isvParams, bizContent, null, null); + JSONObject bizData = response.getData(); + String oriRespType = bizData.getString("oriRespType"); + if(RyxpayKit.RESP_BIZ_ING.equals(oriRespType)){ + return ChannelRetMsg.waiting(); + }else if(RyxpayKit.RESP_BIZ_FAIL.equals(oriRespType)){ + return ChannelRetMsg.confirmFail(response.getData().getString("oriRespCode"),response.getData().getString("oriRespMsg")); + }else if(RyxpayKit.RESP_BIZ_SUCCESS.equals(oriRespType)){ + return ChannelRetMsg.confirmSuccess(response.getSmzfMsgId(),response.getData().getString("channelTradeNo") ,response.getChannelMsgId(),null); + } + return ChannelRetMsg.waiting(); + } + + /** + * 退款权限 + * @param settleType + * @param applyId + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayBizEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayBizEntity.java new file mode 100644 index 0000000..08ec6e2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayBizEntity.java @@ -0,0 +1,53 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.text.DateFormat; + +/** + * TODO + * 瑞银信支付业务公共参数 + * @author crystal + * @date 2024/2/29 13:48 + */ +@Data +@NoArgsConstructor +public class PayBizEntity { + + public static final String DEFAULT_VERSION = "1.0.0"; + + private String version; + + /** + * 取值范围 + * 合作方相关报文:01 + * 扫码支付平台相关报文:02 + */ + private String msgType; + + /** + * 平台返回流水号 + */ + private String smzfMsgId; + + + private String reqDate; + + /** + * 业务参数 + */ + private JSONObject data; + + + public PayBizEntity(JSONObject data,String msgId) { + this.version = DEFAULT_VERSION; + this.msgType = "01"; + this.smzfMsgId = msgId; + this.reqDate = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMAT); + this.data = data; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayReqEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayReqEntity.java new file mode 100644 index 0000000..79441fb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayReqEntity.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * TODO + * 瑞银信支付公共参数封装 + * @author crystal + * @date 2024/2/29 11:53 + */ +@Setter +@Getter +public class PayReqEntity { + + + /** + *不知道是啥参数 + */ + private String cooperator; + + /** + * 加密数据 + */ + private String encryptData; + + /** + * 加密秘钥 + */ + private String encrtptKey; + + /** + * 交易类型 + */ + private String tranCode; + + /** + * 请求唯一表示,代表订单号 长度不能超过12 + */ + private String reqMsgId; + + /** + * 请求回调地址 + */ + private String callBack; + + /** + * 签名 + */ + private String signData; + + + public Map toMap() { + Map map = new HashMap<>(); + map.put("encryptData", Collections.singletonList(this.getEncryptData())); + map.put("encryptKey",Collections.singletonList(this.getEncrtptKey())); + map.put("cooperator",Collections.singletonList(this.getCooperator())); + map.put("signData",Collections.singletonList(this.getSignData())); + map.put("tranCode",Collections.singletonList(this.getTranCode())); + map.put("callBack",Collections.singletonList(this.getCallBack())); + map.put("reqMsgId",Collections.singletonList(this.getReqMsgId())); + return map; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayRespEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayRespEntity.java new file mode 100644 index 0000000..a445095 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/PayRespEntity.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; + +/** + * TODO + * + * @author crystal + * @date 2024/2/29 16:28 + */ +@Data +public class PayRespEntity implements Serializable { + + private String respCode; + + private String respMsg; + + private String respType; + + private JSONObject data; + + private String smzfMsgId; + + private String channelMsgId; + + private String msgType; + + private String reqDate; + + private String version; + + private String respDate; + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/ReqMethod.java new file mode 100644 index 0000000..8ecb233 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/ReqMethod.java @@ -0,0 +1,149 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import cn.hutool.crypto.Mode; +import cn.hutool.crypto.Padding; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.symmetric.AES; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 11:52 + */ +@Data +public class ReqMethod { + + /** + * 进件统一域名 + */ + private final static String INCOME_DOMAIN = "https://rjp.ruiyinxin.com/nms"; + + /** + * 交易统一域名 + */ + private final static String TRADE_DOMAIN = "https://qr.ruiyinxin.com"; + + + @Getter + @AllArgsConstructor + public enum Method{ + + MERCHANT_INCOME("/ims/merch/simpleApply",INCOME_DOMAIN,"商户入驻"), + + MERCHANT_INCOME_RESULT("/ims/merch/queryMerchResult",INCOME_DOMAIN,"进件结果"), + + MERCHANT_QUERY("/ims/merch/getById",INCOME_DOMAIN,"获取商户信息"), + + MERCHANT_UPDATE_SETTLE_CARD("/ims/merch/updateSettleCard",INCOME_DOMAIN,"修改结算卡"), + + MERCHANT_UPDATE_MERC_NAME("/ims/merch/updateMerName",INCOME_DOMAIN,"修改商户简称和经营名称"), + + MERCHANT_CARD_EXPIRE_APPLY("/ims/cardExpire/submitApply",INCOME_DOMAIN,"证件到期补充资料申请"), + + MERCHANT_UPDATE_RATE("/ims/merch/updateRate",INCOME_DOMAIN,"修改费率"), + + MERCHANT_TODAY_SETTLE_QUERY("/ims/tranSt/tranStTodayList",INCOME_DOMAIN,"当日结算查询"), + + MERCHANT_SETTLE_QUERY("/ims/tranSt/tranStList",INCOME_DOMAIN,"历史结算查询"), + + TRADE_ORDER("/ydzf/ydzf-smzf",TRADE_DOMAIN,"交易相关接口"), + + TRADE_REFUND("/ydzf/admin/ydzf-smzf001",TRADE_DOMAIN,"退款相关接口"), + + OTHER_WX_CONFIG("/ydzf/wechat/gateway",TRADE_DOMAIN,"微信支付参数配置") + + ; + private final String method; + + private final String domain; + + private final String desc; + + } + + + /** + * 接口服务码 + */ + @Getter + @AllArgsConstructor + public enum ServiceCode{ + + SMZF002("SMZF002",Method.TRADE_ORDER,"扫码支付"), + + SMZF003("SMZF003",Method.TRADE_ORDER,"条码支付"), + + SMZF004("SMZF004",Method.TRADE_REFUND,"申请退款"), + + SMZF005("SMZF005",Method.TRADE_REFUND,"撤销交易"), + + SMZF006("SMZF006",Method.TRADE_ORDER,"交易查询"), + + SMZF008("SMZF008",Method.TRADE_ORDER,"交易异步通知"), + + SMZF010("SMZF010",Method.TRADE_ORDER,"公众号支付"), + + SMZF014("SMZF014",Method.TRADE_ORDER,"微信APP支付"), + SMZF015("SMZF014",Method.TRADE_ORDER,"订单关闭"), + + SMZF016("SMZF016",Method.TRADE_ORDER,"服务窗支付"), + + SMZF017("SMZF017",Method.TRADE_ORDER,"银联二维码JS支付"), + + SMZF018("SMZF018",Method.TRADE_ORDER,"微信小程序支付"), + + SMZF019("SMZF019",Method.TRADE_ORDER,"银联二维码JS支付获取用户userId"), + + JSAPI_PATH("JSAPI_PATH",Method.OTHER_WX_CONFIG,"微信支付授权目录配置"), + + SUB_APPID("SUB_APPID",Method.OTHER_WX_CONFIG,"微信绑定子商户APPID配置"), + + SUBSCRIBE_APPID("SUBSCRIBE_APPID",Method.OTHER_WX_CONFIG,"微信推荐关注APPID配置"), + + CONFIG_QUERY("CONFIG_QUERY",Method.OTHER_WX_CONFIG,"微信公众号支付商户参数查询"), + + ; + private final String value; + + private final Method method; + + private final String desc; + + } + + /** + * 获取请求接口地址 + * @param method + * @return + */ + public static String getUrl(Method method){ + return method.getDomain() + method.getMethod(); + } + + + public static void main(String[] args) { + String aa = "{\"signData\":\"MsCu6T33QiOCVk/9Eo14+MDgRA7cozwNLH6AO4f3D9BcIJp3a//MG2KKgAcPcXOuDuP4MaTL2VV0KBHk9WeJpT/qUFh6vbkWnojNFdjodmiI6tgBdKkvm+xkpA78SZqLJjXp6x0mbzyCogM79ncNxHvpTqZLdeyn8kFjwgQtVPLnj8jaaRweiobdDT0UkiIV367d9+5i82BIPyKPa9ah+9oZ4P/IzsVNAsIx51aLKW/OC7Dv5M5BJzFAYTE2TATN+REZqmxUHuSVjAg944vrQbVuZEsaNQxqpT/F9JzjLffTkhvKdxwVb3yBwVsxXbuVNNDjIPQsyG9X051NaE0tRQ==\",\"ext\":\"\",\"encryptData\":\"nHGS0DI3iKOLTvi9R/gaWPExQVDQy8nP+iL7jy9amVp5jmMFvszA4GVpzliWRvY6vzqWj/rJSyHOpcLSPGBwPwX9ZvImWTlD8J0knW+U9WCqM+bhJkYpftrprbNs73UZNw3glA06gnths2NcZ/+lty1ispoy2XFhIUWtt+lH8OIc9IZVrJ3E7BCI7lj+63HmSbx+OiWbuyAFpMVDMhucwRBdRMgHAqCh0x/UR/AXmlO4OuS7O7Btwh6+T3KetYpntWir6jL0f7YLA//vjqxQwtFgNWDCxIxeYQs+upXrnQGavHzlMCphXi6+BdnVdZWnzdv/j4DH6OeO01uueqlWeQF61MXtg5cBeBgJ2uPIRG+jMHO6EydHSMzudezvBJlsqgatSWqgcRqQd2/WeUf13azP/cL2vbM8TSnVMQ2ycI54kSiBluJD6EHEab2MmCZia2skskrnYd6DVoj0U7jL1O1iW4BJgYGtV149nrZtq6CAcYLZMC6vbdcExtJ4R9293LNlNDXOJmczdNAoI+oLGzV6mWKs6WSiCR0Q2xGLZuIZVB68cBU8zNCjQ8nELWZAuntkMDOi7Fq9UOPadnubHr3AH4E9L0867p1h6r9dG05uUISBKOov1lKbIEFYx52AsLSDSqw3s/p32zwOELGm+ca7xEd0uzkoRTtNJwGMSJ/338r2r4HK+UVhk2slFJeIXNCPd91qKiG5mGV68GsXFi2gNdJHtMbwJ3RVdYCxPjoHFqiERNmACkaTf4pagM94UzpGrejxJ1bnFZopj5tDOhioVJxQdakJ5ORL8JfzbG3oGM+8moKHmRvT3FomELIraZ02XG0BMGPJ3UgQz9arOeJgF7/rxjhqLR0KV5xRfw+M40sNekUbg91ifhYeju3YC29Y3VhnwxyIA54+DbcwzRmoJNGA9lGP+JiBmLCGweFkcJjVoyiSlkiFxW49Nmsx\",\"tranCode\":\"SMZF018\",\"encryptKey\":\"F8S63fIo04aeXg+IW1mcdvoA3xNWrwPVAohDtQ1HAQwNYoWPGFtGi0pf/VQkxK2vSitvKjIyi274hbf+br9nKhyqNyG+itIO2Hq4mMt3XaK/KcvZ7Z9BAJD8XLQ0U413VmSCxghvnCaat9wbLG8pqUcto1fnulSoNvHe3lmldtMO1jiBQC+05yX5pmcHOWfNqt8IsLcO4onmHA6ud0oiBXHunKHNrfySXLVaJx4tTj0Rnc/Yhit/hBg4pDbgv4cyvM+wzGbNl6nIR/hL/7qfGv57DgukzAQ79PdWljE2FKDekBVKZK9hjNSz4v6Xisc7SPGpwTSEABeNNNk0fJIz+g==\",\"reqMsgId\":\"20240301142354367U9PB2\"}"; + JSONObject resp = JSON.parseObject(aa); + String resEncryptData = resp.getString("encryptData"); + String resEncryptKey = resp.getString("encryptKey"); + String cooPaiKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDConKuuoKWDDpUDDW+aSlhxpoPHEIk3RKJG0PGNh/qlOfR8QYgGRyK4Ml1W3TgAvG+W50H3o2HK7k4Prr0nHSgvte/NgYbrTUo+M0eJyWyMkKY+A0PczeYtX0rmeWd1xjnR7BnXM/Rxj1NFP13+gkecBSnBmShH9T6CJnnD4rrJLG9PbCuq1CevXNSRklAMuufncW9uXeKT946cALDZwpNQKTHHLJUuxV4OjE1nCbSTk6HuLSf7pt3mooilEo9GoqGOOV4Zc/8TgpzCHBJnm81VatEytYcm/4FDcOzt/VJSQIYJWJJni07hmpXqIqG0TFGFsJaYqp84yznj1I73fmZAgMBAAECggEBAJ33Rmi1iyLIzdZFCqF9rE5k58h3wN82ZcLNVBZc+05iiDuGCNioSNgWVKthDNx6x0UeCbbHU8pvHCagExBQov+LpILWD+MKkuir9Z4RW7DixdZtC/yMIIVaVzq57vhKCTY8otlhJHI3GK2k6YskbZ48jSZ6M9Xphetga7hyjucENXNXa9OE+UJGhEzWF0hkD8GL1Umd2WO1AMgg2xIb2gpN5SF5zC9/3hj+iuexJBFJbvjbK6QB/OG3hEEkrAW+NEBcZEZHHUpw3xx9o8gEVTYnHKttgYMjBMZ+wqmGMaOOgmpps7jw3sj1E7KzMqARO/zn6eOd+NPZt8Q/WHMuTzkCgYEA/29N8mCtDVjUNjTFmrXWC8qSYDgGOV9L33YgDBsPwUM11R0k4vkU9C47ERKAWJKqh7u4UoUjct9loYHrCoOCif/8wjpTskMdmfTrwQU+oRVwPDQHC7WYpBoSgUZpZeuZDUxyr2BIqQ3oCKLkOou0bkQFxgGfBdfu75KYQoigCTcCgYEAwxCzv9SlSYEwMqewlF2MQwTgn/Q1lPd1IqMTcxOxn5Ws52eEIzZbqo82j7gWha/Ng1jWP5calkN1ZvROM6vgNKo7ia2AtbVZA74cYBOjTjQ+ZtyVBg0CNz9zYn++9KkCULfjLwixOSok96iziawamH1sHqBwam2N93BJnnpoO68CgYBgXwgTiDICNR9rjCF5q10kebscHkcK4k9n8dNJffRFwCvRSfuevscPEVorqMVPpZY9O6/hQmYLcwmPE8sv3koj8rbUONlXCkdizKsd2fK1J7d+n0qBOnRqhYOxznT5hRfrkoo6bKM9VQfUKlDdXdQnPfbHq9jphXyaWr6ja5SlpQKBgEs1QViQ8Dlq6d5d8SMC/nVIiCKj0ZTh4/O61GDmEvHoj4WYz8WTy7vzA6Jd47EfmyktM03JQKL212kegJhDiGpFyDbJAnsMtIlQ3zfb2nbohba7DWoL0fLjL+WmQ0WpdA8TFzCnNU1JBn/GN5K5HHf2w5z7Vtxx6O6iCIBlyZJZAoGAdEcgEdvR/fBKFN/rkMYXC2pbXPtXL1nnW7Nu39QyqjggLI6nwX310SmponwmPGgc6EMGuPGID8CpIfegpr+2YT9Ma2jHfHHNl/BkAdNx59aiQTcKOoE/7Z84ojMIqfDSHcbRy4y92XDfAVHrDHj503M8/CYpBhdjuuf38Y/W/0U="; + byte[] keyBytes = Base64.getDecoder().decode(resEncryptKey.getBytes(StandardCharsets.UTF_8)); + RSA rsa = SecureUtil.rsa(cooPaiKey,null); + byte[] merchantAESKeyBytes = rsa.decrypt(keyBytes, KeyType.PrivateKey); + byte[] dataBytes = Base64.getDecoder().decode(resEncryptData.getBytes(StandardCharsets.UTF_8)); + AES aes = new AES(Mode.ECB, Padding.PKCS5Padding, merchantAESKeyBytes); + String resXml = aes.decryptStr(dataBytes); + System.out.println("【瑞银信】返回参数解析结果:"+resXml); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessModel.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessModel.java new file mode 100644 index 0000000..9d3efaa --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessModel.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import cn.hutool.core.io.resource.BytesResource; +import lombok.Data; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author DJH + * 瑞银信商户入网相关接口数据参数 + */ +@Data +public class RyxAccessModel { + + + + private String accessId; + + /** + * 订单号,每次传不同值 + */ + private String accessMerchId; + + /** + * 请求时间,时间格式为yyyyMMddHHmmss + */ + private String reqTime; + + /** + * 加密数据,此数据由AES(AES/CBC/PKCS5Padding)进行加密 + */ + private String info; + + /** + * 签名信息,对info原始数据进行签名,签名使用我们的私钥 + */ + private String sign; + + /** + * AES密钥进行加密 + */ + private String encryptKey; + + /** + * 其他参数,可为空 + */ + private Object otherParam; + + /** + * 商户资料图片 + */ + private List files; + +// private List files; + + public static MultiValueMap toMap(RyxAccessModel model) { + MultiValueMap map = new LinkedMultiValueMap<>(); + map.put("accessId", Collections.singletonList(model.getAccessId())); + map.put("accessMerchId", Collections.singletonList(model.getAccessMerchId())); + map.put("reqTime", Collections.singletonList(model.getReqTime())); + map.put("info", Collections.singletonList(model.getInfo())); + map.put("sign", Collections.singletonList(model.getSign())); + map.put("encryptKey", Collections.singletonList(model.getEncryptKey())); + + if (model.getOtherParam() != null) { + map.put("otherParam", Collections.singletonList(model.getOtherParam())); + } + + if (model.getFiles() != null) { + List files = new ArrayList<>(model.getFiles()); + map.put("files", files); + } + + return map; + } + + public void addFile(BytesResource file) { + if (files == null) { + files = new ArrayList<>(); + } + files.add(file); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessResp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessResp.java new file mode 100644 index 0000000..6d64321 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/model/RyxAccessResp.java @@ -0,0 +1,21 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.model; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +@Data +public class RyxAccessResp { + + /** 请求成功码 */ + public static final String RESULT_OK = "0000"; + + /** 请求失败码 */ + public static final String RESULT_ERROR = "0001"; + + private String code; + + private String msg; + + /** 请求结果 */ + private JSONObject result; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliBar.java new file mode 100644 index 0000000..fd5bea6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliBar.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信条码支付 + */ +@Service("ryxpayPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + RyxpayKit.setPayParams(mchAppConfigContext,bizContent,payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + bizContent.put("authCode", bizRQ.getAuthCode()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF003, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliJsapi.java new file mode 100644 index 0000000..63bbf92 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliJsapi.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信 支付宝 jsapi + * + */ +@Service("ryxpayPaymentByAliJsapiService") +public class AliJsapi extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + // 买家支付宝用户ID + bizContent.put("buyerId", bizRQ.getBuyerUserId()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF016, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setAlipayTradeNo(channelRetMsg.getJsapiMsg().getTradeNo()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliLite.java new file mode 100644 index 0000000..56d6719 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/AliLite.java @@ -0,0 +1,73 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信 支付宝 jsapi + * + */ +@Service("ryxpayPaymentByAliLiteService") +public class AliLite extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + // 买家支付宝用户ID + bizContent.put("buyerId", bizRQ.getBuyerUserId()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF016, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setAlipayTradeNo(channelRetMsg.getJsapiMsg().getTradeNo()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxBar.java new file mode 100644 index 0000000..d78abb6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxBar.java @@ -0,0 +1,65 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信微信条码支付 + */ +@Service("ryxpayPaymentByWxBarService") //Service Name需保持全局唯一性 +public class WxBar extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + RyxpayKit.setPayParams(mchAppConfigContext,bizContent,payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + bizContent.put("authCode", bizRQ.getAuthCode()); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + bizContent.put("subAppId", bizRQ.getSubAppid()); + }else{ + bizContent.put("subAppId", oauth2Params.getAppId()); + } + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF003, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxJsapi.java new file mode 100644 index 0000000..6d0adbe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxJsapi.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信 微信jsapi + * + * @author xiaoyu + * + * @date 2022/4/15 15:37 + */ +@Slf4j +@Service("ryxpayPaymentByWxJsapiService") //Service Name需保持全局唯一性 +public class WxJsapi extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 设置请求参数 + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + bizContent.put("userId", bizRQ.getOpenid()); + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + bizContent.put("subAppId", bizRQ.getSubAppid()); + }else { + bizContent.put("subAppId", oauth2Params.getAppId()); + } + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF010, isvParams, bizContent,payOrder.getPayOrderId(),getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxLite.java new file mode 100644 index 0000000..0c99edf --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/WxLite.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:52 + */ +@Slf4j +@Service("ryxpayPaymentByWxLiteService") +public class WxLite extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + // 设置请求参数 + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + JSONObject bizContent = new JSONObject(); + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder, rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + bizContent.put("userId", bizRQ.getOpenid()); + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + // 商户appId + bizContent.put("subAppId", bizRQ.getSubAppid()); + }else { + // 商户appId + bizContent.put("subAppId", oauth2Params.getLiteAppId()); + } + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF018, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + if(channelRetMsg.getJsapiMsg() != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfBar.java new file mode 100644 index 0000000..1d99439 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfBar.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 瑞银信 云闪付条码支付 + */ +@Service("ryxpayPaymentByYsfBarService") //Service Name需保持全局唯一性 +public class YsfBar extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + YsfBarOrderRS res = ApiResBuilder.buildSuccess(YsfBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + bizContent.put("authCode", bizRQ.getAuthCode()); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF003, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfJsapi.java new file mode 100644 index 0000000..be54478 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ryxpay/payway/YsfJsapi.java @@ -0,0 +1,76 @@ +package com.jeequan.jeepay.thirdparty.channel.ryxpay.payway; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayKit; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.RyxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.PayRespEntity; +import com.jeequan.jeepay.thirdparty.channel.ryxpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 云闪付jsapi + * + */ +@Service("ryxpayPaymentByYsfJsapiService") +public class YsfJsapi extends RyxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getUserId())){ + throw new BizException("[userId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + try { + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + RyxpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder, rq); + //加载商户的地区信息 瑞银信必要 + loadMchExtInfo(bizContent,mchAppConfigContext); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + //持卡人ip + bizContent.put("customerIp","127.0.0.1"); + bizContent.put("userId", bizRQ.getUserId()); + if(StringUtils.isNotEmpty(bizRQ.getFrontUrl())){ + bizContent.put("frontUrl",bizRQ.getFrontUrl()); + } + if(StringUtils.isNotEmpty(bizRQ.getFrontFailUrl())){ + bizContent.put("frontFailUrl",bizRQ.getFrontFailUrl()); + } + RyxpayIsvParams isvParams = (RyxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + PayRespEntity response = RyxpayKit.payReqApi(ReqMethod.ServiceCode.SMZF017, isvParams, bizContent, payOrder.getPayOrderId(), getNotifyUrl()); + initCommonResult(response,channelRetMsg,payOrder.getWayCodeType()); + if(channelRetMsg.getJsapiMsg() != null){ + res.setRedirectUrl(channelRetMsg.getJsapiMsg().getRedirectUrl()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandPayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandPayKit.java new file mode 100644 index 0000000..405afaf --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandPayKit.java @@ -0,0 +1,242 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayNormalMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CertUtil; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CryptoUtil; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.HttpClient; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.SDKUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; + +import java.io.IOException; +import java.net.URLDecoder; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 【杉德】支付通道工具包 + * + * @author xiaoyu + * + * @date 2021/12/22 18:08 + */ +@Slf4j +public class SandPayKit { + + /** 默认配置的是UTF-8 **/ + public static String encoding = "UTF-8"; + /** 签名类型,默认01-SHA1+RSA **/ + public static String signType = "01"; + /** 版本号 默认 1.0 **/ + public static String version = "1.0"; + + //http连接超时时间 + public static int connectTimeout = 300000; + //http响应超时时间 + public static int readTimeout = 600000; + + /** + * 加载证书 + * @param mchAppConfigContext + */ + public static void initCert(MchAppConfigContext mchAppConfigContext) { + try { + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SandpayNormalMchParams mchParams = (SandpayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.SANDPAY); + if (mchParams == null) { + log.error("杉德加载证书失败,商户配置不存在"); + } + //加载证书 + CertUtil.init(mchAppConfigContext.getAppId(), channelCertConfigKitBean.getCertFilePath(mchParams.getPublicCert()), channelCertConfigKitBean.getCertFilePath(mchParams.getPrivateCert()), mchParams.getPrivatePassword()); + }catch (Exception e) { + log.error("杉德加载证书异常{}", e.getMessage()); + } + + } + + /** + * 公共请求头参数 + * @param header + * @param method + * @param productId + * @param mchAppConfigContext + */ + public static void setReqHeader(JSONObject header, String method, String productId, MchAppConfigContext mchAppConfigContext) { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SandpayNormalMchParams mchParams = (SandpayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.SANDPAY); + + // 加载证书 + initCert(mchAppConfigContext); + + // 版本号 + header.put("version", version); + // 接口名称 + header.put("method", method); + // 产品编码 + header.put("productId", productId); + // 商户号 + header.put("mid", mchParams.getMid()); + // 接入类型 1-普通商户 2-平台商户 + header.put("accessType", "1"); + // 渠道类型:07-互联网 08-移动端 + header.put("channelType", "07"); + // 请求时间 + header.put("reqTime", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN)); + } + + /** + * 下单请求参数 + * @param body + * @param payOrder + * @param notifyUrl + * @param returnUrl + */ + public static void setPayBody(JSONObject body, PayOrder payOrder, String notifyUrl, String returnUrl) { + + // 支付订单号 + body.put("orderCode", payOrder.getPayOrderId()); + // 订单金额 + body.put("totalAmount", String.format("%12d", payOrder.getFindAmt()).replace(" ", "0")); + // 订单标题 + body.put("subject", payOrder.getSubject()); + // 订单描述 + body.put("body", payOrder.getBody()); + // 订单超时时间 + body.put("txnTimeOut", ""); + // 客户端IP + body.put("clientIp", payOrder.getClientIp()); + // 限定支付方式 送1-限定不能使用贷记卡送 4-限定不能使用花呗 送5-限定不能使用贷记卡+花呗 + body.put("limitPay", ""); + // 异步通知地址 + body.put("notifyUrl", notifyUrl); + // 前台通知地址 + body.put("frontUrl", returnUrl); + // 商户门店编号 + body.put("storeId", ""); + // 商户终端编号 + body.put("terminalId", ""); + // 操作员编号 + body.put("operatorId", ""); + // 清算模式 + body.put("clearCycle", ""); + // 分账信息 + body.put("royaltyInfo", ""); + // 风控信息域 + body.put("riskRateInfo", ""); + // 业务扩展参数 + body.put("bizExtendParams", ""); + // 商户扩展参数 + body.put("merchExtendParams", ""); + // 扩展域 + body.put("extend", ""); + // 分账域 + body.put("accsplitInfo", ""); +// +// JSONObject payExtra=new JSONObject(); +// payExtra.put("userId", "otvxTs_JZ6SEiP0imdhpi50fuSZg"); //付款支付宝用户号 + +// body.put("payMode", "sand_alipay"); //支付模式 +// body.put("payExtra", payExtra.toJSONString()); //支付扩展域 + } + + /** + * 退款请求参数 + */ + public static void setRefundBody(JSONObject body, RefundOrder refundOrder, PayOrder payOrder, String notifyUrl) { + // 商户订单号 + body.put("orderCode", refundOrder.getRefundOrderId()); + // 原商户订单号 + body.put("oriOrderCode", payOrder.getPayOrderId()); + // 退货金额 + body.put("refundAmount", String.format("%12d", refundOrder.getRefundAmount()).replace(" ", "0")); + // 异步通知地址 + body.put("notifyUrl", notifyUrl); + // 退货原因 + body.put("refundReason", "退货测试"); + // 扩展域 + body.put("extend", ""); + } + + + public static JSONObject requestServer(JSONObject body, String reqAddr, String method, String productId, MchAppConfigContext mchAppConfigContext) { + + JSONObject header = new JSONObject(); + setReqHeader(header, method, productId, mchAppConfigContext); + + Map reqMap = new HashMap(); + JSONObject reqJson = new JSONObject(); + reqJson.put("head", header); + reqJson.put("body", body); + String reqStr=reqJson.toJSONString(); + String reqSign; + // 签名 + try { + reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(encoding), CertUtil.getPrivateKey(mchAppConfigContext.getAppId()), "SHA1WithRSA"))); + } catch (Exception e) { + log.error(e.getMessage()); + return null; + } + //整体报文格式 + reqMap.put("charset", encoding); + reqMap.put("data", reqStr); + reqMap.put("signType", signType); + reqMap.put("sign", reqSign); + reqMap.put("extend", ""); + + String result; + try { + log.info("请求报文:\n, {}", JSONObject.toJSONString(reqJson)); + log.info("请求报文:\n, {}", JSONObject.toJSONString(reqSign)); + result = HttpClient.doPost(SandpayConfig.REQ_URL + reqAddr, reqMap, connectTimeout, readTimeout); + log.info("响应报文:\n, {}", result); + result = URLDecoder.decode(result, encoding); + } catch (IOException e) { + log.error(e.getMessage()); + return null; + } + + Map respMap = SDKUtil.convertResultStringToMap(result); + String respData = respMap.get("data"); + String respSign = respMap.get("sign"); + + // 验证签名 + boolean valid; + try { + valid = CryptoUtil.verifyDigitalSign(respData.getBytes(encoding), Base64.decodeBase64(respSign), CertUtil.getPublicKey(mchAppConfigContext.getAppId()),"SHA1WithRSA"); + if(!valid) { + log.error("verify sign fail."); + return null; + } + log.info("verify sign success"); + JSONObject respJson = JSONObject.parseObject(respData); + if(respJson!=null) { + log.info("响应码:[{}]", respJson.getJSONObject("head").getString("respCode")); + log.info("响应描述:[{}]", respJson.getJSONObject("head").getString("respMsg")); + log.info("响应报文:\n, {}", JSONObject.toJSONString(respJson,true)); + }else { + log.error("服务器请求异常!!!"); + } + return respJson; + + } catch (Exception e) { + log.error(e.getMessage()); + return null; + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelNoticeService.java new file mode 100644 index 0000000..5d3a9a6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelNoticeService.java @@ -0,0 +1,129 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CertUtil; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CryptoUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 杉德回调 + * + * @author xiaoyu + * + * @date 2021/12/16 11:30 + */ +@Service +@Slf4j +public class SandpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SANDPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + + JSONObject params = getReqParamJSON(); + // 接收返回参数 + JSONObject dataJson = params.getJSONObject("data"); + JSONObject bodyJson = dataJson.getJSONObject("body"); + // 获取订单号 + String payOrderId = bodyJson.getString("orderCode"); + return MutablePair.of(payOrderId, params); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + + ChannelRetMsg result = ChannelRetMsg.confirmSuccess(null); + + String logPrefix = "【处理杉德支付回调】"; + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + log.info("{} 回调参数, jsonParams:{}", logPrefix, jsonParams); + + // 校验支付回调 + boolean verifyResult = verifyParams(jsonParams, mchAppConfigContext); + // 验证参数失败 + if(!verifyResult){ + throw ResponseException.buildText("ERROR"); + } + log.info("{}验证支付通知数据及签名通过", logPrefix); + + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(SandpayConfig.SUCCESS); + result.setResponseEntity(okResponse); + result.setChannelBizData(jsonParams); + result.setChannelOrderId(jsonParams.getString("transIndex")); + return result; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * 验证杉德支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + // 返回数据 [返回data参数 验签使用String类型] + String dataStr = jsonParams.getString("data"); + JSONObject dataJson = JSONObject.parseObject(dataStr); + + JSONObject bodyObj = dataJson.getJSONObject("body"); + String sign = jsonParams.getString("sign"); + String status = bodyObj.getString("orderStatus"); + + if (StringUtils.isEmpty(status) || !SandpayConfig.NOTIFY_SUCCESS.equals(status)) { + log.info("订单状态未支付成功 [data]={}", status); + return false; + } + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空 [sign] :{}", sign); + return false; + } + + // 加载证书 + SandPayKit.initCert(mchAppConfigContext); + boolean valid = CryptoUtil.verifyDigitalSign(dataStr.getBytes(SandPayKit.encoding), Base64.decodeBase64(sign), + CertUtil.getPublicKey(mchAppConfigContext.getAppId()), "SHA1WithRSA"); + // 验签失败 + if(!valid) { + log.info("【杉德回调】 验签失败! 回调参数:parameter = {}", jsonParams); + return false; + } + return true; + }catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelRefundNoticeService.java new file mode 100644 index 0000000..1dca95e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayChannelRefundNoticeService.java @@ -0,0 +1,129 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CertUtil; +import com.jeequan.jeepay.thirdparty.channel.sandpay.kits.CryptoUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 杉德 退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class SandpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SANDPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + + JSONObject params = getReqParamJSON(); + // 接收返回参数 + JSONObject dataJson = params.getJSONObject("data"); + JSONObject bodyJson = dataJson.getJSONObject("body"); + // 获取订单号 + String refundOrderId = bodyJson.getString("orderCode"); + return MutablePair.of(refundOrderId, params); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + String logPrefix = "【处理盛付通退款回调】"; + try { + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + log.info("{} 接收参数:{} ", logPrefix, jsonParams); + // 校验支付回调 + boolean verifyResult = verifyParams(jsonParams, mchAppConfigContext); + + // 验证参数失败 + if(!verifyResult) { + log.info("{} 验证参数失败, orderId:{}", logPrefix, refundOrder.getRefundOrderId()); + throw ResponseException.buildText("ERROR"); + } + + // 验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp(SandpayConfig.SUCCESS); + JSONObject dataJson = jsonParams.getJSONObject("data"); + JSONObject bodyObj = dataJson.getJSONObject("body"); + // 回调订单状态 + String status = bodyObj.getString("orderStatus"); + ChannelRetMsg result = new ChannelRetMsg(); + + // 渠道订单号 + result.setChannelOrderId(bodyObj.getString("tradeNo")); + // 响应数据 + result.setResponseEntity(okResponse); + // 默认支付中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + if(SandpayConfig.NOTIFY_SUCCESS.equals(status)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + } + + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证杉德支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + // 返回数据 [返回data参数 验签使用String类型] + String dataStr = jsonParams.getString("data"); + String sign = jsonParams.getString("sign"); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空 [sign] :{}", sign); + return false; + } + + // 加载证书 + SandPayKit.initCert(mchAppConfigContext); + boolean valid = CryptoUtil.verifyDigitalSign(dataStr.getBytes(SandPayKit.encoding), Base64.decodeBase64(sign), + CertUtil.getPublicKey(mchAppConfigContext.getAppId()), "SHA1WithRSA"); + // 验签失败 + if(!valid) { + log.info("【杉德回调】 验签失败! 回调参数:parameter = {}", jsonParams); + return false; + } + return true; + }catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPayOrderQueryService.java new file mode 100644 index 0000000..ca6fdac --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPayOrderQueryService.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 杉德查单 + * + * @author xiaoyu + * + * @date 2021/12/16 11:31 + */ +@Service +@Slf4j +public class SandpayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + String logPrefix = "【杉德("+payOrder.getWayCode()+")查单】"; + try { + // 请求参数 + JSONObject bodyJson = new JSONObject(); + bodyJson.put("orderCode", payOrder.getPayOrderId()); + String productId = SandpayConfig.WAY_CODE_MAP.get(payOrder.getWayCode()); + if (StringUtils.isEmpty(productId)) { + log.info("{}支付方式对应的产品编码不存在{}", payOrder.getWayCode(), productId); + return ChannelRetMsg.waiting(); + } + log.info("{} 查询订单 payorderId:{}, 请求参数:{}", logPrefix, payOrder.getPayOrderId(), bodyJson); + JSONObject resJson = SandPayKit.requestServer(bodyJson, SandpayConfig.ORDER_QUERY, SandpayConfig.ORDERQUERY, productId, mchAppConfigContext); + log.info("{} 查询订单 payorderId:{}, 返回结果:{}", logPrefix, payOrder.getPayOrderId(), resJson); + + JSONObject resHead = resJson.getJSONObject("head"); + //请求 & 响应成功, 判断业务逻辑 + String status = resHead.getString("respCode"); + //如果查询交易成功 + if(SandpayConfig.SUCCESS.equals(status)){ + JSONObject jsonObject = resJson.getJSONObject("body"); + String orderStatus = jsonObject.getString("orderStatus"); + if ("00".equals(orderStatus)) { + //交易成功,更新商户订单状态 + return ChannelRetMsg.confirmSuccess(jsonObject.get("payOrderCode").toString()); + }else if ("01".equals(orderStatus)) { + //支付中 + return ChannelRetMsg.waiting(); + }else if ("02".equals(orderStatus)) { + // 失败 + return ChannelRetMsg.confirmFail(); + } + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPaymentService.java new file mode 100644 index 0000000..8fd83e1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayPaymentService.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 杉德下单 + * + * @author xiaoyu + * + * @date 2021/12/22 17:58 + */ +@Service +@Slf4j +public class SandpayPaymentService extends AbstractPaymentService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SANDPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayRefundService.java new file mode 100644 index 0000000..d912a9b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/SandpayRefundService.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.params.sandpay.SandpayConfig; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 杉德官方 + * + * @author xiaoyu + * + * @date 2021/12/16 11:31 + */ +@Slf4j +@Service +public class SandpayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SANDPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + String logPrefix = "【杉德("+payOrder.getWayCode()+")退款】"; + try { + String productId = SandpayConfig.WAY_CODE_MAP.get(payOrder.getWayCode()); + if (StringUtils.isEmpty(productId)) { + log.info("{}支付方式对应的产品编码不存在{}", payOrder.getWayCode(), productId); + return ChannelRetMsg.sysError("支付方式对应的产品编码不存在"); + } + JSONObject bodyJson = new JSONObject(); + SandPayKit.setRefundBody(bodyJson, refundOrder, payOrder, getNotifyUrl()); + log.info("退款订单 payorderId:{}, 请求参数reqParams:{}", payOrder.getPayOrderId(), bodyJson); + JSONObject resJson = SandPayKit.requestServer(bodyJson, SandpayConfig.ORDER_REFUND, SandpayConfig.ORDERREFUND, productId, mchAppConfigContext); + log.info("退款订单 payorderId:{}, 返回结果:{}", payOrder.getPayOrderId(), resJson); + if(resJson == null){ + // 状态不明确 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.UNKNOWN); + } + //请求 & 响应成功, 判断业务逻辑 + JSONObject jsonObject = resJson.getJSONObject("head"); + JSONObject resBodyJson = resJson.getJSONObject("body"); + String status = jsonObject.getString("respCode"); + // 请求成功 + if(SandpayConfig.SUCCESS.equals(status)){ + channelRetMsg.setChannelOrderId(resBodyJson.getString("tradeNo")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + log.info("{} >>> 退款处理中", logPrefix); + }else if (SandpayConfig.WAITING.equals(status)) { + // 退款处理中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(jsonObject.get("respCode").toString()); + channelRetMsg.setChannelErrMsg(jsonObject.get("respMsg").toString()); + log.info("{} >>> 退款失败, {}", logPrefix, resJson); + } + }catch (Exception e) { + // 系统异常 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.SYS_ERROR); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + String logPrefix = "【杉德("+refundOrder.getWayCode()+")[无退款接口]退款查询】"; + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + log.info("{} >>> 退款中", logPrefix); + return channelRetMsg; + } + + /** + * 退款权限 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CertUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CertUtil.java new file mode 100644 index 0000000..b5e7b9a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CertUtil.java @@ -0,0 +1,169 @@ + +package com.jeequan.jeepay.thirdparty.channel.sandpay.kits; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * @ClassName: CertUtil + * @Description: sdk证书工具类,主要用于对证书的加载和使用 + * @version 2.0.0 + */ +public class CertUtil { + + public static final String PUBLIC_KEY = "public_key"; + public static final String PRIVATE_KEY = "private_key"; + + private static final Logger logger = LoggerFactory.getLogger(CertUtil.class); + + private static final ConcurrentHashMap keys = new ConcurrentHashMap(); + + public static void init(String appId, String publicKeyPath, String privateKeyPath, String keyPassword) throws Exception { + // 加载私钥 + initPulbicKey(appId, publicKeyPath); + // 加载公钥 + initPrivateKey(appId, privateKeyPath, keyPassword); + } + + public static PublicKey getPublicKey(String appId) { + return (PublicKey) keys.get(getPublicKeyName(appId)); + } + + public static PrivateKey getPrivateKey(String appId) { + return (PrivateKey) keys.get(getPrivateKeyName(appId)); + } + + private static void initPulbicKey(String appId, String publicKeyPath) throws Exception { + + String classpathKey = "classpath:"; + if (publicKeyPath != null) { + try { + InputStream inputStream = null; + if (publicKeyPath.startsWith(classpathKey)) { + inputStream = CertUtil.class.getClassLoader() + .getResourceAsStream(publicKeyPath.substring(classpathKey.length())); + } else { + inputStream = new FileInputStream(publicKeyPath); + } + PublicKey publicKey = CertUtil.getPublicKey(inputStream); + keys.put(getPublicKeyName(appId), publicKey); + } catch (Exception e) { + logger.error("无法加载公钥[{}]", new Object[] { publicKeyPath }); + logger.error(e.getMessage(), e); + throw e; + } + } + } + + private static void initPrivateKey(String appId, String privateKeyPath, String keyPassword) throws Exception { + + String classpathKey = "classpath:"; + InputStream inputStream = null; + try { + + if (privateKeyPath.startsWith(classpathKey)) { + inputStream = CertUtil.class.getClassLoader() + .getResourceAsStream(privateKeyPath.substring(classpathKey.length())); + } else { + inputStream = new FileInputStream(privateKeyPath); + } + PrivateKey privateKey = CertUtil.getPrivateKey(inputStream, keyPassword); + keys.put(getPrivateKeyName(appId), privateKey); + } catch (Exception e) { + logger.error("无法加载本地私银[" + privateKeyPath + "]"); + logger.error(e.getMessage(), e); + throw e; + }finally { + if(inputStream != null){ + inputStream.close(); + } + inputStream = null; + } + } + + + public static PublicKey getPublicKey(InputStream inputStream) throws Exception { + try { + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate oCert = (X509Certificate) cf.generateCertificate(inputStream); + PublicKey publicKey = oCert.getPublicKey(); + return publicKey; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("读取公钥异常"); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + } + } + } + + /** + * 获取私钥对象 + * @param inputStream 私钥输入流 + * @param password 密钥算法 + * @return 私钥对象 + * @throws Exception + */ + public static PrivateKey getPrivateKey(InputStream inputStream, String password) throws Exception { + try { + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] nPassword = null; + if ((password == null) || password.trim().equals("")) { + nPassword = null; + } else { + nPassword = password.toCharArray(); + } + + ks.load(inputStream, nPassword); + Enumeration enumas = ks.aliases(); + String keyAlias = null; + if (enumas.hasMoreElements()) { + keyAlias = (String) enumas.nextElement(); + } + + PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, nPassword); + return privateKey; + } catch (FileNotFoundException e) { + throw new Exception("私钥路径文件不存在"); + } catch (IOException e) { + throw new Exception(e); + } catch (NoSuchAlgorithmException e) { + throw new Exception("生成私钥对象异常"); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + } + } + } + + protected static String getPublicKeyName(String appId) { + return appId + "_" + PUBLIC_KEY; + } + + protected static String getPrivateKeyName(String appId) { + return appId + "_" + PRIVATE_KEY; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CryptoUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CryptoUtil.java new file mode 100644 index 0000000..1ca51b0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/CryptoUtil.java @@ -0,0 +1,397 @@ + +package com.jeequan.jeepay.thirdparty.channel.sandpay.kits; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; + + +/** + * @ClassName: CryptoUtil + * @Description: sdk加解密工具类,主要用于签名、验证、RSA加解密等 + * @version 2.0.0 + */ + +public class CryptoUtil { + + public static Logger logger = LoggerFactory.getLogger(CryptoUtil.class); + + /** + * 数字签名函数入口 + * + * @param plainBytes + * 待签名明文字节数组 + * @param privateKey + * 签名使用私钥 + * @param signAlgorithm + * 签名算法 + * @return 签名后的字节数组 + * @throws Exception + */ + public static byte[] digitalSign(byte[] plainBytes, PrivateKey privateKey, String signAlgorithm) throws Exception { + try { + Signature signature = Signature.getInstance(signAlgorithm); + signature.initSign(privateKey); + signature.update(plainBytes); + byte[] signBytes = signature.sign(); + + return signBytes; + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("数字签名时没有[%s]此类算法", signAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("数字签名时私钥无效", e); + } catch (SignatureException e) { + throw new Exception("数字签名时出现异常", e); + } + } + + /** + * 验证数字签名函数入口 + * + * @param plainBytes + * 待验签明文字节数组 + * @param signBytes + * 待验签签名后字节数组 + * @param publicKey + * 验签使用公钥 + * @param signAlgorithm + * 签名算法 + * @return 验签是否通过 + * @throws Exception + */ + public static boolean verifyDigitalSign(byte[] plainBytes, byte[] signBytes, PublicKey publicKey, String signAlgorithm) throws Exception { + boolean isValid = false; + try { + Signature signature = Signature.getInstance(signAlgorithm); + signature.initVerify(publicKey); + signature.update(plainBytes); + isValid = signature.verify(signBytes); + return isValid; + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("验证数字签名时没有[%s]此类算法", signAlgorithm), e); + } catch (InvalidKeyException e) { + throw new Exception("验证数字签名时公钥无效", e); + } catch (SignatureException e) { + throw new Exception("验证数字签名时出现异常", e); + } + } + + /** + * 验证数字签名函数入口 + * + * @param plainBytes + * 待验签明文字节数组 + * @param signBytes + * 待验签签名后字节数组 + * @param publicKey + * 验签使用公钥 + * @param signAlgorithm + * 签名算法 + * @return 验签是否通过 + * @throws Exception + */ + public static boolean verifyDigitalSign(byte[] plainBytes, byte[] signBytes, X509Certificate cert, String signAlgorithm) throws Exception { + boolean isValid = false; + try { + Signature signature = Signature.getInstance(signAlgorithm); + signature.initVerify(cert); + signature.update(plainBytes); + isValid = signature.verify(signBytes); + return isValid; + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("验证数字签名时没有[%s]此类算法", signAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("验证数字签名时公钥无效", e); + } catch (SignatureException e) { + throw new Exception("验证数字签名时出现异常", e); + } + } + + /** + * RSA加密 + * + * @param plainBytes + * 明文字节数组 + * @param publicKey + * 公钥 + * @param keyLength + * 密钥bit长度 + * @param reserveSize + * padding填充字节数,预留11字节 + * @param cipherAlgorithm + * 加解密算法,一般为RSA/ECB/PKCS1Padding + * @return 加密后字节数组,不经base64编码 + * @throws Exception + */ + public static byte[] RSAEncrypt(byte[] plainBytes, PublicKey publicKey, int keyLength, int reserveSize, String cipherAlgorithm) + throws Exception { + int keyByteSize = keyLength / 8; // 密钥字节数 + int encryptBlockSize = keyByteSize - reserveSize; // 加密块大小=密钥字节数-padding填充字节数 + int nBlock = plainBytes.length / encryptBlockSize;// 计算分段加密的block数,向上取整 + if ((plainBytes.length % encryptBlockSize) != 0) { // 余数非0,block数再加1 + nBlock += 1; + } + + try { + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + + // 输出buffer,大小为nBlock个keyByteSize + ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * keyByteSize); + // 分段加密 + for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) { + int inputLen = plainBytes.length - offset; + if (inputLen > encryptBlockSize) { + inputLen = encryptBlockSize; + } + + // 得到分段加密结果 + byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen); + // 追加结果到输出buffer中 + outbuf.write(encryptedBlock); + } + + outbuf.flush(); + outbuf.close(); + return outbuf.toByteArray(); + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm)); + } catch (NoSuchPaddingException e) { + throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("无效密钥", e); + } catch (IllegalBlockSizeException e) { + throw new Exception("加密块大小不合法", e); + } catch (BadPaddingException e) { + throw new Exception("错误填充模式", e); + } catch (IOException e) { + throw new Exception("字节输出流异常", e); + } + } + + /** + * RSA解密 + * + * @param encryptedBytes + * 加密后字节数组 + * @param privateKey + * 私钥 + * @param keyLength + * 密钥bit长度 + * @param reserveSize + * padding填充字节数,预留11字节 + * @param cipherAlgorithm + * 加解密算法,一般为RSA/ECB/PKCS1Padding + * @return 解密后字节数组,不经base64编码 + * @throws Exception + */ + public static byte[] RSADecrypt(byte[] encryptedBytes, PrivateKey privateKey, int keyLength, int reserveSize, String cipherAlgorithm) + throws Exception { + int keyByteSize = keyLength / 8; // 密钥字节数 + int decryptBlockSize = keyByteSize - reserveSize; // 解密块大小=密钥字节数-padding填充字节数 + int nBlock = encryptedBytes.length / keyByteSize;// 计算分段解密的block数,理论上能整除 + + try { + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + + // 输出buffer,大小为nBlock个decryptBlockSize + ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize); + // 分段解密 + for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) { + // block大小: decryptBlock 或 剩余字节数 + int inputLen = encryptedBytes.length - offset; + if (inputLen > keyByteSize) { + inputLen = keyByteSize; + } + + // 得到分段解密结果 + byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen); + // 追加结果到输出buffer中 + outbuf.write(decryptedBlock); + } + + outbuf.flush(); + outbuf.close(); + return outbuf.toByteArray(); + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("没有[%s]此类解密算法", cipherAlgorithm)); + } catch (NoSuchPaddingException e) { + throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("无效密钥", e); + } catch (IllegalBlockSizeException e) { + throw new Exception("解密块大小不合法", e); + } catch (BadPaddingException e) { + throw new Exception("错误填充模式", e); + } catch (IOException e) { + throw new Exception("字节输出流异常", e); + } + } + + public static PublicKey toPublicKey(BigInteger exponent,BigInteger modulus) throws Exception { + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modulus, exponent); + PublicKey key = keyFactory.generatePublic(pubSpec); + return key; + } + + public static PrivateKey toPrivateKey(BigInteger exponent,BigInteger modulus) throws Exception { + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + RSAPrivateKeySpec prispec = new RSAPrivateKeySpec(modulus, exponent); + PrivateKey key = keyFactory.generatePrivate(prispec); + return key; + } + + + /** + * AES加密 + * + * @param plainBytes + * 明文字节数组 + * @param keyBytes + * 密钥字节数组 + * @param keyAlgorithm + * 密钥算法 + * @param cipherAlgorithm + * 加解密算法 + * @param IV + * 随机向量 + * @return 加密后字节数组,不经base64编码 + * @throws Exception + */ + public static byte[] AESEncrypt(byte[] plainBytes, byte[] keyBytes, String keyAlgorithm, String cipherAlgorithm, String IV) + throws Exception { + try { + // AES密钥长度为128bit、192bit、256bit,默认为128bit + if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) { + throw new Exception("AES密钥长度不合法"); + } + + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm); + if (StringUtils.trimToNull(IV) != null) { + IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes()); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec); + } else { + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + } + + byte[] encryptedBytes = cipher.doFinal(plainBytes); + + return encryptedBytes; + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm)); + } catch (NoSuchPaddingException e) { + throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("无效密钥", e); + } catch (InvalidAlgorithmParameterException e) { + throw new Exception("无效密钥参数", e); + } catch (BadPaddingException e) { + throw new Exception("错误填充模式", e); + } catch (IllegalBlockSizeException e) { + throw new Exception("加密块大小不合法", e); + } + } + + /** + * AES解密 + * + * @param encryptedBytes + * 密文字节数组,不经base64编码 + * @param keyBytes + * 密钥字节数组 + * @param keyAlgorithm + * 密钥算法 + * @param cipherAlgorithm + * 加解密算法 + * @param IV + * 随机向量 + * @return 解密后字节数组 + * @throws Exception + */ + public static byte[] AESDecrypt(byte[] encryptedBytes, byte[] keyBytes, String keyAlgorithm, String cipherAlgorithm, String IV) + throws Exception { + try { + // AES密钥长度为128bit、192bit、256bit,默认为128bit + if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) { + throw new Exception("AES密钥长度不合法"); + } + + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm); + if (IV != null && StringUtils.trimToNull(IV) != null) { + IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes()); + cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec); + } else { + cipher.init(Cipher.DECRYPT_MODE, secretKey); + } + + byte[] decryptedBytes = cipher.doFinal(encryptedBytes); + + return decryptedBytes; + } catch (NoSuchAlgorithmException e) { + throw new Exception(String.format("没有[%s]此类加密算法", cipherAlgorithm)); + } catch (NoSuchPaddingException e) { + throw new Exception(String.format("没有[%s]此类填充模式", cipherAlgorithm)); + } catch (InvalidKeyException e) { + throw new Exception("无效密钥", e); + } catch (InvalidAlgorithmParameterException e) { + throw new Exception("无效密钥参数", e); + } catch (BadPaddingException e) { + throw new Exception("错误填充模式", e); + } catch (IllegalBlockSizeException e) { + throw new Exception("解密块大小不合法", e); + } + } + + public static byte[] hexString2ByteArr(String hexStr) { + return new BigInteger(hexStr, 16).toByteArray(); + } + public static final byte[] hexStrToBytes(String s) { + byte[] bytes; + bytes = new byte[s.length() / 2]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16); + } + return bytes; + } + /** + * 字符数组16进制字符 + * + * @param bytes + * @return + */ + public static String bytes2string(byte[] bytes, int radix) { + int size = 2; + if (radix == 2) { + size = 8; + } + StringBuilder sb = new StringBuilder(bytes.length * size); + for (int i = 0; i < bytes.length; i++) { + int integer = bytes[i]; + while (integer < 0) { + integer = integer + 256; + } + String str = Integer.toString(integer, radix); + sb.append(StringUtils.leftPad(str.toUpperCase(), size, "0")); + } + return sb.toString(); + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/HttpClient.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/HttpClient.java new file mode 100644 index 0000000..168e405 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/HttpClient.java @@ -0,0 +1,310 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay.kits; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.IOException; +import java.net.URL; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.Map.Entry; + + +/** + * @ClassName: HttpClient + * @Description: 主要用于Http通讯 + * @version 2.0.0 + */ +public class HttpClient { + + private static Logger logger = LoggerFactory.getLogger(HttpClient.class); + + private static final String DEFAULT_CHARSET = "UTF-8"; + + private static SSLContext sslcontext; + + private static SSLConnectionSocketFactory sslsf; + + public static String doPost(String url, Map params, int connectTimeout, int readTimeout) + throws IOException { + return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout); + } + + public static String doPost(String url, Map params, String charset, int connectTimeout, + int readTimeout) throws IOException { + Map headers = new HashMap(); + headers.put("Content-type", "application/x-www-form-urlencoded;charset=" + charset); + return doPost(url, headers, params, charset, connectTimeout, readTimeout); + } + + public static String doPost(String url, Map headers, Map params, + final String charset, int connectTimeout, int readTimeout) throws IOException { + + URL targetUrl = new URL(url); + HttpHost httpHost = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), targetUrl.getProtocol()); + logger.info("host:" + targetUrl.getHost() + ",port:" + targetUrl.getPort() + ",protocol:" + + targetUrl.getProtocol() + ",path:" + targetUrl.getPath()); + + CloseableHttpClient httpclient = getHttpClient(targetUrl); + + try { + HttpPost httpPost = getHttpPost(targetUrl, headers, params, charset, connectTimeout, readTimeout); + + String resp = httpclient.execute(httpHost, httpPost, new ResponseHandler() { + public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + + int status = response.getStatusLine().getStatusCode(); + + logger.info("status:["+status+"]"); + if (status == 200) { + return EntityUtils.toString(response.getEntity(), charset); + } else { + return ""; + } + } + }); + return resp; + } finally { + httpclient.close(); + } + + } + + /** + * 执行HTTP GET请求。 + * + * @param url + * 请求地址 + * @param params + * 请求参数 + * @return 响应字符串 + * @throws IOException + */ + public static String doGet(String url, Map params) throws IOException { + return doGet(url, params, DEFAULT_CHARSET); + } + + /** + * 执行HTTP GET请求。 + * + * @param url + * 请求地址 + * @param params + * 请求参数 + * @param charset + * 字符集,如UTF-8, GBK, GB2312 + * @return 响应字符串 + * @throws IOException + */ + public static String doGet(String url, Map params, String charset) throws IOException { + + Map headers = new HashMap(); + headers.put("Content-type", "application/x-www-form-urlencoded;charset=" + charset); + return doGet(url, headers, params, charset); + + } + + /** + * + * @param url + * @param headers + * @param params + * @param charset + * @return + * @throws IOException + * @throws ClientProtocolException + */ + public static String doGet(String url, Map headers, Map params, + final String charset) throws IOException { + + URL targetUrl = new URL(url); + CloseableHttpClient httpclient = getHttpClient(targetUrl); + + try { + + HttpGet httpGet = getHttpGet(url, headers, params, charset); + + String resp = httpclient.execute(httpGet, new ResponseHandler() { + public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + int status = response.getStatusLine().getStatusCode(); + + logger.info("status:[{}]", new Object[] { status }); + if (status == 200) { + return EntityUtils.toString(response.getEntity(), charset); + } else { + return ""; + } + } + }); + return resp; + + } finally { + httpclient.close(); + } + } + + /** + * + * @param targetUrl + * @param headers + * @param params + * @param charset + * @param isProxy + * @return + * @throws IOException + */ + private static HttpGet getHttpGet(String url, Map headers, Map params, + String charset) throws IOException { + + URL targetUrl = buildGetUrl(url, buildQuery(params, charset)); + HttpGet httpGet = new HttpGet(targetUrl.toString()); + + Iterator> iterator = headers.entrySet().iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + httpGet.setHeader(entry.getKey(), entry.getValue()); + } + + return httpGet; + + } + + /** + * @param isProxy + * + * @param targetUrl @param headers @param params @param charset @param + * connectTimeout @param readTimeout @return @throws IOException @throws + */ + private static HttpPost getHttpPost(URL targetUrl, Map headers, Map params, + String charset, int connectTimeout, int readTimeout) throws IOException { + + HttpPost httpPost = new HttpPost(targetUrl.getPath()); + + Iterator> iterator = headers.entrySet().iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + httpPost.setHeader(entry.getKey(), entry.getValue()); + } + + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeout) + .setConnectTimeout(connectTimeout) // Connection timeout is the timeout until a connection with the + // server is established. + .build(); + httpPost.setConfig(requestConfig); + + StringEntity entity = new StringEntity(buildQuery(params, charset), charset); + httpPost.setEntity(entity); + + return httpPost; + } + + /** + * + * @param targetUrl + * @return + */ + private static CloseableHttpClient getHttpClient(URL targetUrl) { + + CloseableHttpClient httpClient = null; + if ("https".equals(targetUrl.getProtocol())) { + + httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } else { + httpClient = HttpClients.createDefault(); + } + return httpClient; + } + + private static class DefaultTrustManager implements X509TrustManager { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + } + + static { + try { + sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom()); + + // Allow TLSv1 protocol only + sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true;// 默认认证不通过,进行证书校验。 + } + }); + + // javax.net.ssl.SSLPeerUnverifiedException: Host name '192.168.92.124' does not + // match the certificate subject provided by the peer + // (EMAILADDRESS=lsq1015@qq.com, CN=ipay, OU=CMBC, O=XMCMBC, L=Xiamen, + // ST=Fujian, C=CN) + // at + // org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:394) + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public static String buildQuery(Map params, String charset) throws IOException { + + List nvps = new LinkedList(); + + Set> entries = params.entrySet(); + for (Entry entry : entries) { + nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + String str = URLEncodedUtils.format(nvps, charset); + + return str; + } + + public static URL buildGetUrl(String strUrl, String query) throws IOException { + URL url = new URL(strUrl); + if (StringUtils.isEmpty(query)) { + return url; + } + + if (StringUtils.isEmpty(url.getQuery())) { + if (strUrl.endsWith("?")) { + strUrl = strUrl + query; + } else { + strUrl = strUrl + "?" + query; + } + } else { + if (strUrl.endsWith("&")) { + strUrl = strUrl + query; + } else { + strUrl = strUrl + "&" + query; + } + } + + return new URL(strUrl); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/SDKUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/SDKUtil.java new file mode 100644 index 0000000..aea727c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/kits/SDKUtil.java @@ -0,0 +1,118 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay.kits; + + +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +/** + * @ClassName: SDKUtil + * @Description: + * @version 2.0.0 + */ +public class SDKUtil { + + /** + * 将形如key=value&key=value的字符串转换为相应的Map对象 + * + * @param result + * @return + */ + public static Map convertResultStringToMap(String result) { + Map map = null; + try { + + if (StringUtils.isNotBlank(result)) { + if (result.startsWith("{") && result.endsWith("}")) { + System.out.println(result.length()); + result = result.substring(1, result.length() - 1); + } + map = parseQString(result); + } + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return map; + } + + /** + * 解析应答字符串,生成应答要素 + * + * @param str + * 需要解析的字符串 + * @return 解析的结果map + * @throws UnsupportedEncodingException + */ + public static Map parseQString(String str) throws UnsupportedEncodingException { + + Map map = new HashMap(); + int len = str.length(); + StringBuilder temp = new StringBuilder(); + char curChar; + String key = null; + boolean isKey = true; + boolean isOpen = false;// 值里有嵌套 + char openName = 0; + if (len > 0) { + for (int i = 0; i < len; i++) {// 遍历整个带解析的字符串 + curChar = str.charAt(i);// 取当前字符 + if (isKey) {// 如果当前生成的是key + + if (curChar == '=') {// 如果读取到=分隔符 + key = temp.toString(); + temp.setLength(0); + isKey = false; + } else { + temp.append(curChar); + } + } else {// 如果当前生成的是value + if (isOpen) { + if (curChar == openName) { + isOpen = false; + } + + } else {// 如果没开启嵌套 + if (curChar == '{') {// 如果碰到,就开启嵌套 + isOpen = true; + openName = '}'; + } + if (curChar == '[') { + isOpen = true; + openName = ']'; + } + } + if (curChar == '&' && !isOpen) {// 如果读取到&分割符,同时这个分割符不是值域,这时将map里添加 + putKeyValueToMap(temp, isKey, key, map); + temp.setLength(0); + isKey = true; + } else { + temp.append(curChar); + } + } + + } + putKeyValueToMap(temp, isKey, key, map); + } + return map; + } + + private static void putKeyValueToMap(StringBuilder temp, boolean isKey, String key, Map map) + throws UnsupportedEncodingException { + if (isKey) { + key = temp.toString(); + if (key.length() == 0) { + throw new RuntimeException("QString format illegal"); + } + map.put(key, ""); + } else { + if (key.length() == 0) { + throw new RuntimeException("QString format illegal"); + } + map.put(key, temp.toString()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliBar.java new file mode 100644 index 0000000..f3eebb0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliBar.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.sandpay.SandPayKit; +import com.jeequan.jeepay.thirdparty.channel.sandpay.SandpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 杉德 支付宝 条码支付 +* +* @author pangxiaoyu +* +* @date 2021/6/8 18:11 +*/ +@Slf4j +@Service("sandPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends SandpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + String logPrefix = "【杉德支付宝("+payOrder.getWayCode()+")支付】"; + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + JSONObject bodyJson = new JSONObject(); + // 通道类型 + bodyJson.put("payTool", "0401"); + // 付款码: 用户 APP 展示的付款条码或二维码 + bodyJson.put("authCode", bizRQ.getAuthCode().trim()); + // 杉德 统一参数赋值 + SandPayKit.setPayBody(bodyJson, payOrder, getNotifyUrl(), getReturnUrl()); + + // 发送请求 + log.info("{}, 下单请求发送数据:{}", logPrefix, bodyJson); + JSONObject resJson = SandPayKit.requestServer(bodyJson, SandpayConfig.ORDER_PAY, SandpayConfig.ORDERPAY_BARPAY, SandpayConfig.PRODUCTID_ALIPAY_QR, mchAppConfigContext); + log.info("{}, 下单请求返回数据:{}", logPrefix, resJson); + //请求 & 响应成功, 判断业务逻辑 + JSONObject resHead = resJson.getJSONObject("head"); + String status = resHead.getString("respCode"); + try { + if(SandpayConfig.SUCCESS.equals(status)){ + + JSONObject resBody = resJson.getJSONObject("body"); + String channelOrderNo = resBody.get("payOrderCode").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + res.setPayData(resBody.toJSONString()); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + } + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliJsapi.java new file mode 100644 index 0000000..4e3e4b4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/AliJsapi.java @@ -0,0 +1,93 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayConfig; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.sandpay.SandPayKit; +import com.jeequan.jeepay.thirdparty.channel.sandpay.SandpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 杉德 支付宝 jsapi + * + * @author xiaoyu + * + * @date 2021/12/22 18:11 + */ +@Slf4j +@Service("sandpayPaymentByAliJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends SandpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + String logPrefix = "【杉德支付宝("+payOrder.getWayCode()+")支付】"; + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + + // 设置请求参数 + JSONObject bodyJson = new JSONObject(); + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + // 付款支付宝用户号 + JSONObject paramsJson = new JSONObject(); + paramsJson.put("userId", bizRQ.getBuyerUserId()); + bodyJson.put("payExtra", paramsJson.toJSONString()); + // 支付模式 + bodyJson.put("payMode", "sand_alipay"); + SandPayKit.setPayBody(bodyJson, payOrder, getNotifyUrl(), getReturnUrl()); + + // 发送请求 + log.info("{}, 下单请求发送数据:{}", logPrefix, bodyJson); + JSONObject resJson = SandPayKit.requestServer(bodyJson, SandpayConfig.ORDER_PAY, SandpayConfig.ORDERPAY, SandpayConfig.PRODUCTID_ALIPAY_JSAPI, mchAppConfigContext); + log.info("{}, 下单请求返回数据:{}", logPrefix, resJson); + //请求 & 响应成功, 判断业务逻辑 + JSONObject resHead = resJson.getJSONObject("head"); + String status = resHead.getString("respCode"); + if(SandpayConfig.SUCCESS.equals(status)){ + //付款信息 + JSONObject resBody = resJson.getJSONObject("body"); + String channelOrderNo = resBody.get("tradeNo").toString(); + channelRetMsg.setChannelOrderId(channelOrderNo); + + // 获取payInfo + JSONObject credentialJosn = resBody.getJSONObject("credential"); + JSONObject payInfoJson = credentialJosn.getJSONObject("params").getJSONObject("payInfo"); + res.setAlipayTradeNo(payInfoJson.getString("trade_no")); + res.setPayData(JSON.toJSONString(new ChannelJsapiMsg(payInfoJson.getString("trade_no")))); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(resHead.getString("respCode")); + channelRetMsg.setChannelErrMsg(resHead.getString("respMsg")); + } + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/SandH5.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/SandH5.java new file mode 100644 index 0000000..21f3e2e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sandpay/payway/SandH5.java @@ -0,0 +1,162 @@ +package com.jeequan.jeepay.thirdparty.channel.sandpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.SandH5OrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.SandH5OrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.thirdparty.channel.sandpay.SandpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.net.URLEncoder; +import java.util.Date; + +/** + * 杉德H5收银台 + * + * @author jmdhappy + * + * @date 2021/12/31 12:11 + */ +@Service("sandpayPaymentBySandpH5Service") //Service Name需保持全局唯一性 +public class SandH5 extends SandpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + SandH5OrderRQ bizRQ = (SandH5OrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getProductCode())){ + throw new BizException("产品编码[productCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + SandH5OrderRS res = ApiResBuilder.buildSuccess(SandH5OrderRS.class); + + SandH5OrderRQ req = (SandH5OrderRQ) rq; + // 支付类型 + String productCode = req.getProductCode(); + String payType = ""; + switch (productCode) { + case "02000001": // 聚合码 + payType = "pczm"; + break; + case "02010002": // 微信公众号(微信公众号H5) + payType = "public"; + break; + case "02010005": // APP包装微信小程序(微信sdk) + payType = "sdk"; + break; + case "02010006": // 微信小程序(云函数h5) + payType = "applet"; + break; + case "02010007": // 微信小程序(云函数sdk) + payType = "sdk"; + break; + case "02020002": // 支付宝生活号(支付宝H5) + payType = "alipayh5"; + break; + case "02020004": // APP包装支付宝(支付宝sdk) + payType = "sdk"; + } + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + + SandpayNormalMchParams mchParams = (SandpayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.SANDPAY); + + // 拼接服务端参数 + JSONObject paramsJson = new JSONObject(); + // 当前接口版本号 + paramsJson.put("version", "10"); + // 商户编号 + paramsJson.put("mer_no", mchParams.getMid()); + // 商户密钥, 手机APK工具 生成的key1 + paramsJson.put("mer_key", mchParams.getKey1()); + // 商户订单号(最小长度12位) + paramsJson.put("mer_order_no", payOrder.getPayOrderId()); + // 订单创建时间 yyyyMMddHHmmss + paramsJson.put("create_time", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN)); + // 订单金额(单位:元,1分=0.01元 + paramsJson.put("order_amt", AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); + // 回调地址 + paramsJson.put("notify_url", getNotifyUrl()); + // 支付后返回的商户显示页面,没有就填"" + paramsJson.put("return_url", getReturnUrl()); + // 用户所在客户端的真实ip其中的“.”替换为“_” 。如 192_168_0_1 + paramsJson.put("create_ip", payOrder.getClientIp().replace(".", "_")); + // 门店号 没有就填默认值 000000 + paramsJson.put("store_id", "000000"); + // 清算模式(不参加签名)0-T1(默认);1-T0;2-D0;3-D1 + paramsJson.put("clear_cycle", ""); + // 支付扩展域 + paramsJson.put("pay_extra", req.getPayExtra()); + // 分账标识 NO无分账,YES有分账 + paramsJson.put("accsplit_flag", "NO"); + // 签名类型,默认MD5 + paramsJson.put("sign_type", "MD5"); + + String sign = JeepayKit.getSign(paramsJson, mchParams.getMd5Key()); + // MD5签名结果 + paramsJson.put("sign", sign); + // 订单失效时间 yyyyMMddHHmmss(不参加签名) + paramsJson.put("expire_time", DateUtil.format(payOrder.getExpiredTime(), DatePattern.PURE_DATETIME_PATTERN)); + // 商品名称(不参加签名) + paramsJson.put("goods_name", payOrder.getSubject()); + // 支付产品,多个以英文逗号分隔,具体产品见产品编码文档(不参加签名) + paramsJson.put("product_code", productCode); + // 跳转scheme(不参与签名)没有就填默认值 sandcash://scpay + paramsJson.put("jump_scheme", "sandcash://scpay"); + // 终端/网站参数 + paramsJson.put("meta_option", req.getMetaOption()); + + // 对参数做URL编码处理 + URLEncoder(paramsJson, "mer_key", "goods_name", "notify_url", "return_url", "pay_extra", "meta_option"); + + if("sdk".equals(payType)) { + String urlParams = JeepayKit.genUrlParams(paramsJson); + res.setFormContent(urlParams); + }else { + String urlParams = JeepayKit.genUrlParams(paramsJson); + res.setPayUrl("https://sandcash.mixienet.com.cn/h5/?" + urlParams + "#/" + payType); + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + + /** + * + * @param obj 需要处理的JSON对象 + * @param keys 需要编码的key集合 + */ + void URLEncoder(JSONObject obj, String... keys) { + for(String key : keys) { + if(StringUtils.isNotBlank(obj.getString(key))) { + obj.put(key, URLEncoder.encode(obj.getString(key))); + } + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayBillDownloadService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayBillDownloadService.java new file mode 100644 index 0000000..ed133d3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayBillDownloadService.java @@ -0,0 +1,128 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.csv.CsvData; +import cn.hutool.core.text.csv.CsvRow; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.CheckBatch; +import com.jeequan.jeepay.core.model.bill.ChannelBill; +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 com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ExcelUtil; +import com.jeequan.jeepay.db.entity.CheckChannelBill; +import com.jeequan.jeepay.thirdparty.channel.AbstractBillDownloadService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.zip.ZipEntry; + +/* +* 随行付 对账单下载 +*/ +@Slf4j +@Service +public class SxfpayBillDownloadService extends AbstractBillDownloadService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + /** + * billType 对账单类型,枚举值 + * 取值范围: + * 00 交易 + * 01 结算 + * 02 分账 + * 03 硬件交易 + * 04 微校交易 + * 05 转账 + */ + @Override + public ChannelBillRS convertStandardBill(ChannelBillRQ channelBillRQ, MchAppConfigContext mchAppConfigContext, Date billDate, String ifCode){ + + String logPrefix = "【随行付对账单下载】"; + SxfpayIsvParams isvParams = (SxfpayIsvParams) channelBillRQ.getIsvParams(); + ChannelBillRS channelBillRes = new ChannelBillRS(); + String channelMchNo = channelBillRQ.getChannelMchNo(); // 渠道商户号 + // 账单文件流 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try { + JSONObject bizContent = new JSONObject(); + bizContent.put("billDate",DateUtil.format(DateUtil.offsetDay(billDate,1), DatePattern.PURE_DATE_PATTERN)); + bizContent.put("billType","00"); + //获取随行付的对账单 + JSONObject response = SxfpayKit.reqApi(ReqMethod.Method.CHECK_GET_FILE, isvParams, bizContent); + // 下载对账单,写入文件输出流 + HttpUtil.download(response.getString("downloadUrl"), byteArrayOutputStream, false); + // 上传oss + String url = upload2Oss(ifCode, channelMchNo, billDate, ".csv", IoUtil.toStream(byteArrayOutputStream)); + // 生成附带对账文件下载地址的解析成功的批次 + CheckBatch checkBatch = genReleaseSuccessCheckBatch(ifCode, billDate, channelMchNo, url); + // 渠道账单列表 + List channelBillList = new ArrayList<>(); + // 渠道总退款金额 + long channelTotalRefundAmount = 0; + // 读取对账单 csv文件 + CsvData csvRows = ExcelUtil.readCsvData(byteArrayOutputStream, CharsetUtil.CHARSET_UTF_8); + List rows = csvRows.getRows(); + // 遍历行 + for (int i = 1; i < rows.size(); i++) { + CsvRow csvRow = rows.get(i); + // getRawList返回一个List列表,列表的每一项为CSV中的一个单元格 + List rawList = csvRow.getRawList(); + if (rawList.size() > 22) { + String thirdMchNo = rawList.get(0).trim(); + ChannelBill channelBill = new ChannelBill(); + channelBill.setBatchNo(checkBatch.getBatchNo()); + channelBill.setBillDate(billDate); + channelBill.setIfCode(ifCode); + channelBill.setChannelMchNo(thirdMchNo); + channelBill.setChannelOrderNo(rawList.get(3).trim()); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(9).trim()))); + channelBill.setChannelFeeAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(11).trim()))); + channelBill.setChannelSuccessAt(DateUtil.parse(rawList.get(14).trim(),"yyyyMMdd HH:mm:ss")); + if (StringUtils.equals(rawList.get(7).trim(), "00")) { + channelBill.setOrderId(rawList.get(2).trim()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_PAY); + channelBill.setChannelState((byte) 2); + }else if (StringUtils.equals(rawList.get(7).trim(), "01")) { + channelBill.setOrderId(rawList.get(2).trim()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND); + channelBill.setChannelState((byte) 5); + channelBill.setOrgPayOrderId(rawList.get(4).trim()); + channelTotalRefundAmount += channelBill.getChannelAmount(); + } + channelBillList.add(channelBill); + } + } + checkBatch.setChannelTotalRefundAmount(channelTotalRefundAmount); + checkBatch.setChannelTotalAmount(checkBatch.getChannelTotalAmount() + Math.abs(channelTotalRefundAmount)); + channelBillRes.setCheckBatch(checkBatch); + channelBillRes.setChannelBillList(channelBillList); + return channelBillRes; + }catch (Exception e) { + log.error("{}, 解析对账文件失败,", logPrefix, e); + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage())); + return channelBillRes; + }finally { + IoUtil.close(byteArrayOutputStream); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelNoticeService.java new file mode 100644 index 0000000..a33539c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelNoticeService.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 银盛支付 回调接口实现类 + */ +@Service +@Slf4j +public class SxfpayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + JSONObject reqParamJSON = getReqParamJSON(); + String payOrderId = reqParamJSON.getString("ordNo"); + return MutablePair.of(payOrderId, reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject respJson = (JSONObject) JSONObject.toJSON(params); + boolean verifyResult = verifyParams(respJson, mchAppConfigContext, payOrder); + // 验证参数失败 + if(!verifyResult){ + throw ResponseException.buildText("error"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = jsonResp(SxfpayKit.ok()); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + result.setChannelUserId(respJson.getString("openid")); + result.setChannelOrderId(respJson.getString("uuid")); + //如果是支付宝 则需要去除前两位 + result.setPlatformOrderNo(respJson.getString("transactionId")); + result.setPlatformMchOrderNo(respJson.getString("sxfUuid")); + String drType = respJson.getString("drType"); + if(StringUtils.isNotEmpty(drType)){ + switch (drType){ + case "1": + result.setDrType(CS.DrType.DEBIT.getType()); + break; + case "2": + result.setDrType(CS.DrType.CREDIT.getType()); + break; + default: + result.setDrType(CS.DrType.OTHER.getType()); + break; + } + }else{ + result.setDrType(CS.DrType.OTHER.getType()); + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证随行付支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, PayOrder payOrder) { + try { + String logPrefix = "【处理[随行付]支付回调】"; + log.info("{} 回调参数: jsonParams:{}", logPrefix, jsonParams); + String sign = jsonParams.getString("sign"); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空:sign:{}", sign); + return false; + } + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), payOrder.getIfCode()); + return SxfpayKit.checkSign(jsonParams, isvParams); + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelRefundNoticeService.java new file mode 100644 index 0000000..abc6a6b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelRefundNoticeService.java @@ -0,0 +1,104 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 随行付退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class SxfpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject params = getReqParamJSON(); + // 接收返回参数 + String refundOrderId = params.getString("ordNo"); + return MutablePair.of(refundOrderId, params); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + String logPrefix = "【处理随行付退款回调】"; + try { + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + log.info("{} 接收参数:{} ", logPrefix, jsonParams); + // 校验支付回调 + boolean verifyResult = verifyParams(jsonParams, mchAppConfigContext); + // 验证参数失败 + if(!verifyResult) { + log.info("{} 验证参数失败, orderId:{}", logPrefix, refundOrder.getRefundOrderId()); + throw ResponseException.buildText("ERROR"); + } + // 验签成功后判断上游订单状态 + ResponseEntity okResponse = jsonResp(SxfpayKit.ok()); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + // 渠道订单号 + result.setChannelOrderId(jsonParams.getString("uuid")); + // 响应数据 + result.setPlatformOrderNo(jsonParams.getString("transactionId")); + result.setPlatformMchOrderNo(jsonParams.getString("sxfUuid")); + result.setChannelUserId(jsonParams.getString("openid")); + result.setChannelErrCode(jsonParams.getString("bizCode")); + result.setChannelErrMsg(jsonParams.getString("bizMsg")); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证随行付退款通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + String sign = jsonParams.getString("sign"); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空 [sign] :{}", sign); + return false; + } + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + return SxfpayKit.checkSign(jsonParams, isvParams); + }catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelUserService.java new file mode 100644 index 0000000..1c47e55 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayChannelUserService.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** +* 银盛 获取银联userId实现类 +* +* @author jmdhapy +* +* @date 2022/3/17 16:51 +*/ +@Service +@Slf4j +public class SxfpayChannelUserService implements IChannelUserService { + + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("ysRedirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + log.info("{} userAuthCode={}, appUpIdentifier={}", logPrefix, userAuthCode, appUpIdentifier); + JSONObject bizContent = new JSONObject(); + // 用户授权码 + bizContent.put("userAuthCode", userAuthCode); + // 银联支付标识 + bizContent.put("paymentApp", appUpIdentifier); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.OTHER_GET_UNION_USERID, isvParams, bizContent); + return respBizData.getString("data"); + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayGetApplymentDataService.java new file mode 100644 index 0000000..13a51c9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayGetApplymentDataService.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.db.entity.BankBranch; +import com.jeequan.jeepay.service.impl.BankBranchService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class SxfpayGetApplymentDataService implements IGetApplymentDataService { + + @Autowired + private BankBranchService bankBranchService; + + /** + * @cityCode 这里取城市名称. + */ + @Override + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { +// Assert.notBlank(bankName, "银行名称不能为空"); + Page page = new Page<>(); + bankBranchService.pageByArea(page, cityCode, bankName, branchName); + + return page.getRecords().stream().map( t -> ((JSONObject) JSON.toJSON(t))).collect(Collectors.toList()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..0fdaec8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchAlipayConfigService.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class SxfpayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + // 支付宝渠道拓展地址 + result.setSignUrl(isvParams.getAliUrl()); + // 图片类型 + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (StringUtils.isEmpty(mchApplyment.getChannelMchNo())) { + result.setErrInfo("随行付商户号为空"); + return result; + } + // 银盛商户号 + String mercId = suJson.getString("mercId"); + + LambdaQueryChainWrapper zfbSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + MchSubInfoEntity zfb = zfbSubInfoQuery.one(); + + if (zfb == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + zfb = zfbSubInfoQuery.one(); + } + + if (zfb == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if ("01".equals(zfb.getStatus())) { + result.setChannelSubMchId(zfb.getSubMchId()); + } else { + result.setState("未报备"); + result.setErrInfo("[" + zfb.getRemark() + "]"); + return result; + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("subMchId", zfb.getSubMchId()); + + // 发送请求 + JSONObject response = SxfpayKit.reqApi(ReqMethod.Method.ALI_CERT_STATUS, isvParams, bizContent); + if (!"0000".equals(response.getString("bizCode"))) { +// throw new BizException(response.getString("bizMsg")); + + result.setState("04"); + result.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + + return result; + } + + // 解密后数据 + String authState = response.getString("checkResult"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + if ("AUTHORIZED".equals(authState)) { + result.setState("已授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } else if ("CLOSED".equals(authState)) { + result.setState("已销户"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_LOGOFF).update(); + } else { + result.setState("未授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..0624e7f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchApplymentNotifyService.java @@ -0,0 +1,215 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ApplymentNotify; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Service("sxfpayIsvmchApplymentNotifyService") +public class SxfpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private MchModifyApplymentService modifyApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Autowired + private MchApplymentService mchApplymentService; + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + try { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + ApplymentNotify applymentNotify = reqParamJSON.toJavaObject(ApplymentNotify.class); + + return MutablePair.of(urlApplyId, applymentNotify); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + private void handleModifyApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String changeSysFlowId = applymentNotify.getApplicationId(); + + MchModifyApplyment modifyApplyment = getModifyApplymentByChannelApplyNo(changeSysFlowId); + + IIsvmchModifyApplymentService isvmchModifyApplymentService = IsvFactory.getIsvMchModifyApplymentService(CS.IF_CODE.YSPAY); + + if (mchApplyment.getState() == com.jeequan.jeepay.db.entity.MchApplyment.STATE_SUCCESS) { + // 已经变更完成,直接退出 + return; + } + + // 其他状态统一定为驳回 + if ("05".equals(applymentNotify.getTaskStatus())) { // 变更成功 + handleSuccessfulChange(modifyApplyment, mchApplyment, isvmchModifyApplymentService); + } else { + handleRejectedState(modifyApplyment, applymentNotify.getSuggestion()); + } + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment) { + ApplymentNotify applymentNotify = (ApplymentNotify) params; + + MutablePair result = new MutablePair<>(); + + if (ApplymentNotify.TASK_TYPE_INCOME.equals(applymentNotify.getTaskType())) { + // 进件 + if ("1".equals(applymentNotify.getTaskStatus())) { + MchApplyment resultMchApplyment = new MchApplyment(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + resultMchApplyment.setState(MchApplyment.STATE_SUCCESS); + resultMchApplyment.setChannelMchNo(applymentNotify.getMno()); + result.left = resultMchApplyment; + result.right = retOk(null); + + // 收集子商户信息 + collSubMerchInfo(mchApplyment, applymentNotify); + + return result; + } + + // 驳回 + if ("2".equals(applymentNotify.getTaskStatus())) { + MchApplyment resultMchApplyment = new MchApplyment(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + resultMchApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultMchApplyment.setApplyErrorInfo("[" + applymentNotify.getSuggestion() + "]"); + result.left = resultMchApplyment; + result.right = retOk(null); + + return result; + } + } + + if (ApplymentNotify.TASK_TYPE_MODIFY.equals(applymentNotify.getTaskType())) { + handleModifyApply(applymentNotify, mchApplyment); + } + + return null; + } + + private MchModifyApplyment getModifyApplymentByChannelApplyNo(String channelApplyNo) { + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + qWrapper.eq(MchModifyApplymentEntity::getChannelApplyNo, channelApplyNo); + return mchInfoConverter.toModel(modifyApplymentService.getOne(qWrapper)); + } + + /** + * 收集子商户信息 + * @param mchApplyment + * @param applymentNotify + */ + public void collSubMerchInfo(MchApplyment mchApplyment, ApplymentNotify applymentNotify) { + List repoInfo = applymentNotify.getRepoInfo(); +// List subInfoList = new ArrayList<>(); + for (ApplymentNotify.Repo repo : repoInfo) { + MchSubInfoEntity item = new MchSubInfoEntity(); + item.setSubMchType(repo.getChildNoType()); + item.setSubMchId(repo.getChildNo()); + item.setStatus(repo.getRepoStatus()); + item.setChannelId(repo.getChannelId()); + item.setRemark(repo.getErrMessage()); + item.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + // TODO 随行付没有银联和网联的标识 + item.setSubMchWay("SXF"); + item.setMainUse(1); + item.setExt(((JSONObject) JSON.toJSON(repo))); + item.setMchApplyId(mchApplyment.getApplyId()); + //TODO 防止重复插入导致报错 + try { + mchSubInfoService.save(item); + }catch (DuplicateKeyException e){ + } +// subInfoList.add(item); + } +// mchSubInfoService.saveBatch(subInfoList); + } + + private void handleSuccessfulChange(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) { + MutablePair mchModifyPair; + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + mchModifyPair = isvmchModifyApplymentService.localModifyBase(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + mchModifyPair = isvmchModifyApplymentService.localModifySettlement(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_RATE: + mchModifyPair = isvmchModifyApplymentService.localModifyRate(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + default: + mchModifyPair = new MutablePair<>(modifyApplyment, mchApplyment); + } + + updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight()); + } + + private void updateModificationState(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + MchModifyApplymentEntity dbEntity = mchInfoConverter.toDbEntity(modifyApplyment); + com.jeequan.jeepay.db.entity.MchApplyment dbEntity1 = mchInfoConverter.toDbEntity(mchApplyment); + + // 状态变更就更新 + if (!modifyApplyment.getState().equals(mchApplyment.getState())) { + modifyApplymentService.updateById(dbEntity); + + // 变更成功就更新商户数据 + if (modifyApplyment.getState() == com.jeequan.jeepay.db.entity.MchApplyment.STATE_SUCCESS) { + mchApplymentService.updateById(dbEntity1); + } + } + } + + private void handleRejectedState(MchModifyApplyment modifyApplyment, String note) { + MchModifyApplymentEntity result = new MchModifyApplymentEntity(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + result.setApplyErrorInfo("[" + note + "]"); + result.setState(com.jeequan.jeepay.db.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + modifyApplymentService.updateById(result); + } + + @Override + public ResponseEntity retOk(Object params) { + JSONObject param = new JSONObject(); + param.put("code", "success"); + param.put("msg", "成功"); + + return IIsvmchApplymentNotifyService.super.retOk(param); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..e476c32 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchModifyApplymentService.java @@ -0,0 +1,296 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.SxfpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class SxfpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + SxfpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, SxfpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + SxfpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, SxfpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setAuthSettle(mchModifyData.getIllegal()); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setLetterOfAuthPic(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put("updateCallBackUrl", getCallbackUrl(mchApplyment.getIfCode(), mchApplyment.getApplyId())); + param.put("mno", mchApplyment.getChannelMchNo()); + param.put("mecDisNm", mchModifyData.getMchShortName()); + + try { + JSONObject applyRespData = SxfpayKit.reqApi(ReqMethod.Method.MERCHANT_INFO_MODIFY, isvParams, param); + + String applicationId = applyRespData.getString("applicationId"); + String bizCode = applyRespData.getString("bizCode"); + + if (SxfpayKit.SUCCESS_CODE.equals(bizCode)) { + resultModifyApplyment.setChannelApplyNo(applicationId); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + String bizMsg = applyRespData.getString("bizMsg"); + resultModifyApplyment.setChannelApplyNo(applicationId); + resultModifyApplyment.setApplyErrorInfo("[" + bizMsg + "]"); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + String remark = "随行付基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("随行付基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + + // 上传图片 + if ("B".equals(mchModifyData.getSettAccountType())) { + String openingAccountLicensePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountLicenseImg(), "04"); + param.put("openingAccountLicensePic", openingAccountLicensePic); + } else { + String bankCardPositivePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountLicenseImg(), "05"); + param.put("bankCardPositivePic", bankCardPositivePic); + } + + if ("Y".equals(mchModifyData.getIllegal())) { + // 非法人结算, 上传身份证图片 + String settlePersonIdcardPositive = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountIdcard1Img(), "07"); + param.put("settlePersonIdcardPositive", settlePersonIdcardPositive); + String settlePersonIdcardOpposite = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getSettAccountIdcard2Img(), "08"); + param.put("settlePersonIdcardOpposite", settlePersonIdcardOpposite); + String letterOfAuthPic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, mchModifyData.getNonLegSettleAuthPic(), "26"); + param.put("letterOfAuthPic", letterOfAuthPic); + } + + param.put("updateCallBackUrl", getCallbackUrl(mchApplyment.getIfCode(), mchApplyment.getApplyId())); + param.put("actNo", mchModifyData.getSettAccountNo()); + param.put("actTyp", mchModifyData.getSettAccountType().equals("B")? "00": "01"); + param.put("actNoType", "00"); + param.put("stmManIdNo", mchModifyData.getSettAccountIdcardNo()); + param.put("actNm", mchModifyData.getSettAccountName()); + param.put("lbnkNo", mchModifyData.getBankSubCode()); + param.put("mno", mchApplyment.getChannelMchNo()); + + try { + JSONObject applyRespData = SxfpayKit.reqApi(ReqMethod.Method.MERCHANT_INFO_MODIFY, isvParams, param);; + + String applicationId = applyRespData.getString("applicationId"); + String bizCode = applyRespData.getString("bizCode"); + + if (SxfpayKit.SUCCESS_CODE.equals(bizCode)) { + resultModifyApplyment.setChannelApplyNo(applicationId); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + } else { + String bizMsg = applyRespData.getString("bizMsg"); + resultModifyApplyment.setChannelApplyNo(applicationId); + resultModifyApplyment.setApplyErrorInfo("[" + bizMsg + "]"); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + String remark = "随行付基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("随行付基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + throw new BizException("当前通道不支持该操作"); + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + resultModifyApplyment.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + MchApplyment mchApplyment = mchDataPair.getRight(); + + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject param = new JSONObject(); + param.put("applicationId", modifyApplyment.getModifyApplyId()); + + JSONObject bizData = SxfpayKit.reqApi(ReqMethod.Method.MERCHANT_AUDIT_RESULT_QUERY, isvParams, param); + String status = bizData.getString("status"); + String bizCode = bizData.getString("bizCode"); + + if (!SxfpayKit.SUCCESS_CODE.equals(bizCode)) { + throw new BizException("查询变更结果失败"); + } + + String bizMsg = bizData.getString("bizMsg"); + String suggestion = bizData.getString("suggestion"); + String mno = bizData.getString("mno"); + String taskStatus = bizData.getString("taskStatus"); + + switch (taskStatus) { + case "5": + // 成功 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + return handleSuccessCase(modifyApplyment, mchDataPair); + case "4": + // 待审核 + break; + default: + // 失败 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + suggestion + "]"); + + return new MutablePair<>(resultModifyApplyment, null); + } + + return mchDataPair; + } + + private MutablePair handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair mchDataPair) { + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + default: + return mchDataPair; + } + } + + private String processChannelValue(String channelVal, JSONObject bizData) { + JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal); + channelValJSON.putAll(bizData); + return channelValJSON.toJSONString(); + } + + private String getCallbackUrl(String ifCode, String applyId) { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + ifCode + "/" + applyId; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchWxConfigService.java new file mode 100644 index 0000000..d2dea7f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayIsvmchWxConfigService.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class SxfpayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + // 同步后子商户信息还是为空,则抛出异常 + if (StringUtils.isEmpty(mchApplyment.getChannelMchNo())) { + result.setErrInfo("随行付商户号为空"); + return result; + } + LambdaQueryChainWrapper wxSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + MchSubInfoEntity wx = wxSubInfoQuery.one(); + + if (wx == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + wx = wxSubInfoQuery.one(); + } + + if (wx == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if ("01".equals(wx.getStatus())) { + result.setChannelSubMchId(wx.getSubMchId()); + } else { + result.setState("未报备"); + result.setErrInfo("[" + wx.getRemark() + "]"); + return result; + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("subMchId", wx.getSubMchId()); + + // 发送请求 + JSONObject response = SxfpayKit.reqApi(ReqMethod.Method.WX_CERT_STATUS, isvParams, bizContent); + if (!"0000".equals(response.getString("bizCode"))) { +// throw new BizException(response.getString("bizMsg")); + + result.setState("04"); + result.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + + return result; + } + + // 解密后数据 + String authState = response.getString("authStatus"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authState)) { + result.setState("已授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } else { + result.setState("未授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayKit.java new file mode 100644 index 0000000..d274486 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayKit.java @@ -0,0 +1,228 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.core.utils.JeepayRSA2Kit; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqEntity; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.RespEntity; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 11:01 + */ +@Slf4j +public class SxfpayKit { + + public static final String SUCCESS_CODE = "0000"; + + public static final String EXT_SUCCESS_CODE = "2002"; + + public static final String EXT_SUCCESS_CODE_1 = "00"; + + /** + * 设置支付通用参数 + * + * @param bizContent + * @param payOrder + */ + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent, PayOrder payOrder, UnifiedOrderRQ rq) { + bizContent.put("mno", mchAppConfigContext.getMchApplyment().getChannelMchNo()); + bizContent.put("ordNo", payOrder.getPayOrderId()); + bizContent.put("payType", payOrder.getWayCodeType()); + bizContent.put("amt", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + bizContent.put("trmIp", "127.0.0.1"); + long between = DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE); + bizContent.put("timeExpire", between); + bizContent.put("subject", payOrder.getSubject()); + Integer limitPay = rq.getLimitPay(); + if (limitPay == null || limitPay == -1) { + bizContent.put("limitPay", "00"); + } else { + bizContent.put("limitPay", "01"); + } + if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(payOrder.getWayCodeType())) { + Integer hbFqNum = rq.getHbFqNum(); + if (hbFqNum != null) { + bizContent.put("hbFqNum", hbFqNum); + bizContent.put("hbFqPercent", rq.getHbFqPercent()); + } + } + } + + + /** + * 发起请求 返回业务参数 + * + * @param method + * @param reqData + * @return + */ + public static JSONObject reqApi(ReqMethod.Method method, SxfpayIsvParams isvParams, JSONObject reqData) { + ReqEntity reqEntity = new ReqEntity(isvParams.getOrgId(), reqData); + initSign(reqEntity, isvParams); + log.info("【随行付】请求参数:{}", JSON.toJSONString(reqEntity)); + HttpResponse response = HttpRequest.post(ReqMethod.getUrl(method)).body(JSON.toJSONString(reqEntity)).execute(); + if (!response.isOk()) { + throw new BizException("请求失败,请求状态异常"); + } + log.info("【随行付】响应参数:{}", response.body()); + JSONObject respBody = JSON.parseObject(response.body()); + if (respBody == null) { + throw new BizException("请求成功,接口返回参数异常,接口无响应参数"); + } + if (!checkSign(respBody, isvParams)) { + throw new BizException("随行付返回参数验签失败"); + } + RespEntity respEntity = respBody.toJavaObject(RespEntity.class); + if (!SUCCESS_CODE.equals(respEntity.getCode())) { + throw new BizException(respEntity.getMsg()); + } + JSONObject respData = respEntity.getRespData(); + if (!SUCCESS_CODE.equals(respData.get("bizCode")) && !EXT_SUCCESS_CODE.equals(respData.get("bizCode")) && !EXT_SUCCESS_CODE_1.equals(respData.get("bizCode"))) { + throw new BizException("["+respData.get("bizCode")+"]" + respData.getString("bizMsg")); + } + return respData; + } + + /** + * 发起请求 返回业务参数 + * + * @param method + * @return + */ + public static String reqUpload(ReqMethod.Method method, SxfpayIsvParams isvParams, String imgUrl, String pictureType) { + + Assert.notNull(imgUrl, "缺少类型为{}的图片", pictureType); + + // 下载文件 + byte[] imgFileByteArray = null; + try { + ByteArrayOutputStream baos = ImageUtils.compressNetPic(imgUrl, 2048 * 1024); + imgFileByteArray = baos.toByteArray(); + } catch (IORuntimeException e) { + e.printStackTrace(); + } + + log.info("【随行付】上传图片:{}, 图片类型为{}", imgUrl, pictureType); + HttpResponse response = HttpRequest.post(ReqMethod.getUrl(method)) + .form("orgId", isvParams.getOrgId()) + .form("reqId", IdUtil.fastUUID()) + .form("pictureType", pictureType) + .form("file", imgFileByteArray, IdUtil.fastUUID() + ".jpg") + .execute(); + if (!response.isOk()) { + log.info("请求失败, {}", JSON.toJSONString(response)); + throw new BizException("请求失败,请求状态异常"); + } + log.info("【随行付】响应参数:{}", response.body()); + JSONObject respBody = JSON.parseObject(response.body()); + if (respBody == null) { + throw new BizException("请求成功,接口返回参数异常,接口无响应参数"); + } + if (!checkSign(respBody, isvParams)) { + throw new BizException("随行付返回参数验签失败"); + } + RespEntity respEntity = respBody.toJavaObject(RespEntity.class); + if (!SUCCESS_CODE.equals(respEntity.getCode())) { + throw new BizException(respEntity.getMsg()); + } + JSONObject respData = respEntity.getRespData(); + if (!SUCCESS_CODE.equals(respData.get("bizCode")) && !EXT_SUCCESS_CODE.equals(respData.get("bizCode"))) { + throw new BizException(respData.getString("bizMsg")); + } + return respData.getString("PhotoUrl"); + } + + /** + * 校验接口返回参数 + * + * @param respBody + */ + public static boolean checkSign(JSONObject respBody, SxfpayIsvParams isvParams) { + try { + //如果参数中签名值为空,则不校验签名 + String isSign = respBody.getString("sign"); + if(StringUtils.isEmpty(isSign)){ + return true; + } + String sign = (String)respBody.remove("sign"); + return JeepayRSA2Kit.verify(getStrSort(respBody), isvParams.getPublicKey(), sign); + } catch (Exception e) { + return false; + } + } + + /** + * 获取签名字符串 + * @param map + * @return + */ + public static String getStrSort(Map map) { + ArrayList list = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + list.add(entry.getKey() + "=" + entry.getValue() + "&"); + } + int size = list.size(); + String[] arrayToSort = list.toArray(new String[size]); + Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + sb.append(arrayToSort[i]); + } + return sb.substring(0, sb.length() - 1); + } + + /** + * 初始化签名 + * + * @param reqEntity + * @param isvParams + */ + public static void initSign(ReqEntity reqEntity, SxfpayIsvParams isvParams) { + try { + log.info("加签私钥,{}", isvParams.getPrivateKey()); + String sign = JeepayRSA2Kit.getSign(reqEntity.getSignContent(), isvParams.getPrivateKey()); + reqEntity.setSign(sign); + } catch (Exception e) { + e.printStackTrace(); + throw new BizException("签名异常"); + } + } + + /** + * 响应接口参数 + * + * @return + */ + public static Object ok() { + JSONObject result = new JSONObject(); + result.put("code", "success"); + result.put("msg", "成功"); + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApiService.java new file mode 100644 index 0000000..b6f94a6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApiService.java @@ -0,0 +1,193 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +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 com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; + +/** + * TODO + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class SxfpayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * 配置微信相关参数 + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + ReqMethod.Method method = ReqMethod.Method.MERCHANT_WX_CONF; + JSONObject bizData = new JSONObject(); + bizData.put("mno",applyment.getChannelMchNo()); + bizData.put("subMchId", mchRq.getSubMchNo()); + if(ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())){ + bizData.put("type","03"); + bizData.put("jsapiPath",mchRq.getJsapiPath()); + }else{ + bizData.put("type","01"); + bizData.put("subAppid",mchRq.getAppid()); + if(ChannelMchRq.Type.PUBLIC.getType().equals(mchRq.getType())){ + bizData.put("accountType","00"); + }else { + bizData.put("accountType","01"); + } + } + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(applyment); + JSONObject respBizData = SxfpayKit.reqApi(method, isvParams, bizData); + String bizCode = respBizData.getString("bizCode"); + String bizMsg = respBizData.getString("bizMsg"); + ChannelRetMsg retMsg = new ChannelRetMsg(); + retMsg.setChannelBizData(respBizData); + retMsg.setChannelErrCode(bizCode); + retMsg.setChannelErrMsg(bizMsg); + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + if(!SxfpayKit.SUCCESS_CODE.equals(bizCode)){ + throw new BizException(bizMsg); + } + return retMsg; + } + + /** + * 查询结算信息 + * @param settleRq + * @param isvNo + * @param isvParams + * @return + */ + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, SxfpayIsvParams isvParams) { + JSONObject bizData = new JSONObject(); + bizData.put("mno",settleRq.getMercNo()); + if(StringUtils.isNotBlank(settleRq.getBillNo())){ + bizData.put("serialNo",settleRq.getBillNo()); + }else{ + bizData.put("queryTime",DateUtil.format(settleRq.getStartDate(),DatePattern.PURE_DATE_PATTERN)); + } + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.SETTLE_QUERY, isvParams, bizData); + JSONArray infos = respBizData.getJSONArray("settleInfo"); + if(infos == null || infos.isEmpty()){ + return null; + } + List result = new ArrayList<>(infos.size()); + infos.forEach(item -> { + JSONObject itemData = ((JSONObject) item); + JSONObject data = new JSONObject(); + data.put("billNo",itemData.getString("serialNo")); + data.put("isvNo", isvNo); + data.put("accountNo",itemData.getString("settleBnkNo")); + data.put("accountName",itemData.getString("settleAccountNm")); + if(StringUtils.isNotBlank(itemData.getString("amount"))){ + long stlAmt = itemData.getBigDecimal("amount").multiply(BigDecimal.valueOf(100)).longValue(); + data.put("settleAmt",stlAmt); + } +// if(StringUtils.isNotBlank(itemData.getString("fee"))){ +// long feeAmt = itemData.getBigDecimal("fee").multiply(BigDecimal.valueOf(100)).longValue(); +// data.put("fee",feeAmt); +// } + SettleState settleStatus = SettleState.getVal(itemData.getString("settleStatus")); + switch (settleStatus){ + case SUCCESS: + data.put("state", SettleInfo.SUCCESS); + break; + case PAYING: + data.put("state", SettleInfo.PROGRESS); + break; + case TICKET: + data.put("state", SettleInfo.TICKET); + break; + case WAIT: + data.put("state", SettleInfo.WAIT); + break; + default: + data.put("state", SettleInfo.FAIL); + break; + } + data.put("channelState",settleStatus.getState()); + String remark = StringUtils.isNotEmpty(itemData.getString("refReason")) ? itemData.getString("refReason") : settleStatus.getDesc(); + data.put("remark",remark); + data.put("bankName",itemData.getString("settleLbnk")); + String settleTime = itemData.getString("settleTime"); + if(StringUtils.isNotEmpty(settleTime)){ + DateTime settle = DateUtil.parse(settleTime, DatePattern.PURE_DATETIME_PATTERN); + data.put("settleDate",DateUtil.format(settle,DatePattern.NORM_DATE_PATTERN)); + data.put("settleTime",settle); + }else{ + data.put("settleTime",new Date()); + } + data.put("extra", itemData.toString()); + result.add(data); + }); + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState{ + + SUCCESS("S","付款成功"), + + WAIT("I","待付款"), + + FAIL("F","付款失败"), + + PAYING("P","付款中"), + + EXPRIE("N","失效"), + + TICKET("R","退票"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state){ + SettleState[] values = values(); + for (SettleState val:values) { + if(val.getState().equals(state)){ + return val; + } + } + return WAIT; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApplymentService.java new file mode 100644 index 0000000..7b23ca2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayMchApplymentService.java @@ -0,0 +1,273 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.SxfpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service("sxfpayMchApplymentService") +public class SxfpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private SysConfigService sysConfigService; + + public static final String logPrefix = "【银盛商户进件】"; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + public JSONObject getApplymentParams(MchApplyment mchApplyment) { + SxfpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), SxfpayApplymentInfo.class); + + SxfpayIsvParams isvParams = ((SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + JSONObject resultParam = new JSONObject(); + if (!StrUtil.isEmpty(applymentInfo.getMerName())) { + resultParam.put("merName", applymentInfo.getMerName()); + } + resultParam.put("mecDisNm", applymentInfo.getMecDisNm()); + resultParam.put("mblNo", applymentInfo.getMblNo()); +// resultParam.put("operationalType", applymentInfo.getOperationalType()); + resultParam.put("operationalType", "01"); + resultParam.put("haveLicenseNo", applymentInfo.getHaveLicenseNo()); +// resultParam.put("mecTypeFlag", applymentInfo.getMecTypeFlag()); + resultParam.put("mecTypeFlag", "00"); + resultParam.put("cprRegAddr", applymentInfo.getCprRegAddr()); + resultParam.put("regProvCd", applymentInfo.getRegProvCd()); + resultParam.put("regCityCd", applymentInfo.getRegCityCd()); + resultParam.put("regDistCd", applymentInfo.getRegDistCd()); + resultParam.put("mccCd", applymentInfo.getMccCd()); + resultParam.put("csTelNo", applymentInfo.getCsTelNo()); + + List rateInfos = applymentInfo.collQrCodeList(); + resultParam.put("qrcodeList", rateInfos); + +// resultParam.put("specifyWechatChannel", ) +// resultParam.put("specifyALiPayChannel", ) + + resultParam.put("callbackUrl", sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + mchApplyment.getIfCode() + "/" + mchApplyment.getApplyId()); + + if (applymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + resultParam.put("cprRegNmCn", applymentInfo.getCprRegNmCn()); + resultParam.put("registCode", applymentInfo.getRegistCode()); + + if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == applymentInfo.getMerchantType()) { + resultParam.put("licenseMatch", applymentInfo.getLicenseMatch()); + } + + resultParam.put("businessLicStt", applymentInfo.getBusinessLicStt()); + resultParam.put("businessLicEnt", applymentInfo.getBusinessLicEnt()); + } + + resultParam.put("identityName", applymentInfo.getIdentityName()); + resultParam.put("identityTyp", ObjUtil.defaultIfNull(applymentInfo.getIdentityTyp(), "00")); + resultParam.put("identityNo", applymentInfo.getIdentityNo()); + resultParam.put("legalPersonLicStt", applymentInfo.getLegalPersonLicStt()); + resultParam.put("legalPersonLicEnt", applymentInfo.getLegalPersonLicEnt()); + + resultParam.put("actNo", applymentInfo.getActNo()); + resultParam.put("lbnkNo", applymentInfo.getLbnkNo()); + + resultParam.put("actNm", applymentInfo.getActNm()); + resultParam.put("actTyp", applymentInfo.getActTyp()); + + // 对私结算 + if ("01".equals(applymentInfo.getActTyp())) { + resultParam.put("actNoType", ObjUtil.defaultIfNull(applymentInfo.getActNoType(), "00")); + resultParam.put("stmManIdNo", applymentInfo.getStmManIdNo()); + resultParam.put("accountLicStt", applymentInfo.getAccountLicStt()); + resultParam.put("accountLicEnt", applymentInfo.getAccountLicEnt()); + } + + // 上传图片 + if (applymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + String licensePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getLicensePic(), "13"); + resultParam.put("licensePic", licensePic); + } + + String legalPersonidPositivePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getLegalPersonidPositivePic(), "02"); + resultParam.put("legalPersonidPositivePic", legalPersonidPositivePic); + + String legalPersonidOppositePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getLegalPersonidOppositePic(), "03"); + resultParam.put("legalPersonidOppositePic", legalPersonidOppositePic); + + if ("00".equals(applymentInfo.getActTyp())) { + String openingAccountLicensePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getOpeningAccountLicensePic(), "04"); + resultParam.put("openingAccountLicensePic", openingAccountLicensePic); + } else { + String bankCardPositivePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getBankCardPositivePic(), "05"); + resultParam.put("bankCardPositivePic", bankCardPositivePic); + } + + if ("Y".equals(applymentInfo.getAuthSettle())) { + String settlePersonIdcardPositive = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getSettlePersonIdcardPositive(), "07"); + resultParam.put("settlePersonIdcardPositive", settlePersonIdcardPositive); + + String settlePersonIdcardOpposite = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getSettlePersonIdcardOpposite(), "08"); + resultParam.put("settlePersonIdcardOpposite", settlePersonIdcardOpposite); + + String letterOfAuthPic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getLetterOfAuthPic(), "26"); + resultParam.put("letterOfAuthPic", letterOfAuthPic); + } + + String storePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getStorePic(), "10"); + resultParam.put("storePic", storePic); + + String insideScenePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getInsideScenePic(), "11"); + resultParam.put("insideScenePic", insideScenePic); + + String businessPlacePic = SxfpayKit.reqUpload(ReqMethod.Method.MERCHANT_INCOME_PHOTO_UPLOAD, isvParams, applymentInfo.getBusinessPlacePic(), "12"); + resultParam.put("businessPlacePic", businessPlacePic); + + return resultParam; + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + String logPrefix = "【随行付商户进件状态查询】"; + MchApplyment result = new MchApplyment(); + result.setState(mchApplyment.getState()); + result.setApplyId(mchApplyment.getApplyId()); + + if (mchApplyment.getState() == com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING) { + // 资料确认状态查询 + // 获取支付参数 + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContent.put("applicationId", mchApplyment.getChannelApplyNo()); + + // 解密后数据 + JSONObject resData = SxfpayKit.reqApi(ReqMethod.Method.MERCHANT_APPLY_QUERY, isvParams, bizContent); + + String bizMsg = resData.getString("bizMsg"); + String bizCode = resData.getString("bizCode"); + String taskStatus = resData.getString("taskStatus"); + String mno = resData.getString("mno"); + String suggestion = resData.getString("suggestion"); + + if (!SxfpayKit.SUCCESS_CODE.equals(bizCode)) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setChannelVar1(resData.toJSONString()); + result.setApplyErrorInfo("[" + bizMsg + "]"); + return mchApplyment; + } + + result.setApplyErrorInfo(bizCode + "[" + suggestion + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, bizCode, suggestion); + + // 审核成功 + if ("1".equals(taskStatus)) { + result.setChannelMchNo(mno); + result.setSuccResParameter(resData.toString()); + subMchColl(result, resData.getJSONArray("repoInfo")); + } + + // 审核拒绝 + else if ("2".equals(taskStatus)) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + suggestion + "]"); + return result; + + } else { + result.setApplyErrorInfo("[" + suggestion + "]"); + return result; + } + } + + return result; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public void subMchColl(MchApplyment mchApplyment, Object callback) { + JSONArray repoInfo = (JSONArray) callback; + for (int i = 0; i < repoInfo.size(); i++) { + JSONObject repo = repoInfo.getJSONObject(i); + MchSubInfoEntity subInfo = new MchSubInfoEntity(); + subInfo.setSubMchType(repo.getString("childNoType")); + subInfo.setSubMchId(repo.getString("childNo")); + subInfo.setChannelId(repo.getString("channelId")); + subInfo.setRemark(repo.getString("errMessage")); + subInfo.setChannelMchNo(mchApplyment.getChannelMchNo()); + subInfo.setSubMchWay("SXF"); + subInfo.setStatus(repo.getString("repoStatus")); + subInfo.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + subInfo.setExt(repo); + subInfo.setMainUse(1); + subInfo.setMchApplyId(mchApplyment.getApplyId()); + try { + mchSubInfoService.save(subInfo); + } catch (DuplicateKeyException e) { + log.info("重复子商户数据,不做处理"); + } + } + } + + /** + * 重新子商户信息收集方法 + * @param mchApplyment + */ + @Override + public void subMchColl(MchApplyment mchApplyment) { + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + JSONObject bizContent = new JSONObject(); + bizContent.put("mno",mchApplyment.getChannelMchNo()); + JSONObject response = SxfpayKit.reqApi(ReqMethod.Method.MERCHANT_INFO_QUERY, isvParams, bizContent); + JSONArray repoInfo = response.getJSONArray("repoInfo"); + repoInfo.stream().map(item -> (JSONObject)item).forEach(repo -> { + MchSubInfoEntity item = new MchSubInfoEntity(); + item.setSubMchType(repo.getString("childNoType")); + item.setSubMchId(repo.getString("childNo")); + item.setStatus(repo.getString("repoStatus")); + item.setChannelId(repo.getString("channelId")); + item.setRemark(repo.getString("errMessage")); + item.setAuthStatus(MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + // TODO 随行付没有银联和网联的标识 + item.setSubMchWay("SXF"); + item.setMainUse(1); + item.setExt(((JSONObject) JSON.toJSON(repo))); + item.setMchApplyId(mchApplyment.getApplyId()); + try { + mchSubInfoService.save(item); + }catch (DuplicateKeyException e){ + } + }); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderCloseService.java new file mode 100644 index 0000000..ff1772a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderCloseService.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 关闭订单接口实现类 + */ +@Slf4j +@Service +public class SxfpayPayOrderCloseService implements IPayOrderCloseService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + try { + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),payOrder.getIfCode()); + JSONObject bizContent = new JSONObject(); + // 商户号 + bizContent.put("mno", payOrder.getChannelMchNo()); + // 商户订单号 + bizContent.put("origOrderNo", payOrder.getPayOrderId()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_ORDER_CLOSE, isvParams, bizContent); + String tranSts = respBizData.getString("tranSts"); + String uuid = respBizData.getString("uuid"); + switch (tranSts){ + case "CLOSED": + return ChannelRetMsg.confirmSuccess(uuid); + } + return ChannelRetMsg.confirmFail(respBizData.getString("bizCode"),respBizData.getString("bizMsg")); + }catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderQueryService.java new file mode 100644 index 0000000..9944c7e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPayOrderQueryService.java @@ -0,0 +1,84 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 查询订单 随行付 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class SxfpayPayOrderQueryService implements IPayOrderQueryService { + + public static final String SUCCESS = "SUCCESS"; + + public static final String FAIL = "FAIL"; + + public static final String PAYING = "PAYING"; + + public static final String CLOSED = "CLOSED"; + + public static final String CANCELED = "CANCELED"; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + try { + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),payOrder.getIfCode()); + JSONObject bizContent = new JSONObject(); + // 商户号 + bizContent.put("mno", payOrder.getChannelMchNo()); + // 商户订单号 + bizContent.put("ordNo", payOrder.getPayOrderId()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_ORDER_QUERY, isvParams, bizContent); + String tranSts = respBizData.getString("tranSts"); + String uuid = respBizData.getString("uuid"); + String sxfUuid = respBizData.getString("sxfUuid"); + String buyerId = respBizData.getString("buyerId"); + String channelDrType = respBizData.getString("drType"); + String drType = CS.DrType.OTHER.getType(); + if(StringUtils.isNotEmpty(channelDrType)){ + switch (channelDrType){ + case "1": + drType = CS.DrType.DEBIT.getType(); + break; + case "2": + drType = CS.DrType.CREDIT.getType(); + break; + } + } + String transactionId = respBizData.getString("transactionId"); + switch (tranSts){ + case SUCCESS: + ChannelRetMsg retMsg = ChannelRetMsg.confirmSuccess(uuid, transactionId, sxfUuid, drType); + retMsg.setChannelUserId(buyerId); + return retMsg; + case FAIL: + return ChannelRetMsg.confirmFail(uuid,respBizData.getString("bizCode"),respBizData.getString("bizMsg")); + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPaymentService.java new file mode 100644 index 0000000..fd5c993 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayPaymentService.java @@ -0,0 +1,126 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + * 银盛支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Slf4j +@Service +public class SxfpayPaymentService extends AbstractPaymentService { + + /** + * 随行付花呗分期参数支持选项 + */ + public static final int[] ALI_HB_FQ_NUM_ARR = {3,6,12}; + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + public void preCheckAli(UnifiedOrderRQ rq) { + Integer hbFqNum = rq.getHbFqNum(); + if(hbFqNum != null){ + boolean isCheck = Arrays.stream(ALI_HB_FQ_NUM_ARR).anyMatch(num -> num == hbFqNum); + if(!isCheck){ + throw new BizException("支付宝支付花呗分期参数有误,仅可支持数值为"+ StringUtils.join(ALI_HB_FQ_NUM_ARR,",") +"期"); + } + Integer hbFqPercent = rq.getHbFqPercent(); + if(hbFqPercent != null && hbFqPercent != 0){ + throw new BizException("花呗分期商家承担手续费比例目前只支持用户承担手续费"); + } + rq.setHbFqPercent(0); + } + } + + /** + * 统一返回参数解析 + * @param respBizData + * @param res + */ + public void initCommonResult(JSONObject respBizData, ChannelRetMsg res) { + res.setChannelState(ChannelRetMsg.ChannelState.WAITING); + res.setNeedQuery(true); + res.setChannelBizData(respBizData); + res.setChannelErrCode(respBizData.getString("bizCode")); + res.setChannelErrMsg(respBizData.getString("bizMsg")); + if(!SxfpayKit.SUCCESS_CODE.equals(respBizData.getString("bizCode")) && !SxfpayKit.EXT_SUCCESS_CODE.equals(respBizData.getString("bizCode"))){ + res.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + res.setNeedQuery(false); + }else{ + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(respBizData.getString("source")); + jsapiMsg.setAppId(respBizData.getString("payAppId")); + jsapiMsg.setPaySign(respBizData.getString("paySign")); + jsapiMsg.setTimeStamp(respBizData.getString("payTimeStamp")); + jsapiMsg.setNonceStr(respBizData.getString("paynonceStr")); + jsapiMsg.setPayPackage(respBizData.getString("payPackage")); + jsapiMsg.setSignType(respBizData.getString("paySignType")); + jsapiMsg.setRedirectUrl(respBizData.getString("redirectUrl")); + String tranSts = respBizData.getString("tranSts"); + res.setPlatformOrderNo(respBizData.getString("transactionId")); + res.setChannelOrderId(respBizData.getString("uuid")); + res.setPlatformMchOrderNo(respBizData.getString("sxfUuid")); + res.setChannelUserId(respBizData.getString("buyerId")); + if("SUCCESS".equals(tranSts)){ + res.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + res.setNeedQuery(false); + String drType = respBizData.getString("drType"); + if(StringUtils.isNotEmpty(drType)){ + switch (drType){ + case "1": + res.setDrType(CS.DrType.DEBIT.getType()); + break; + case "2": + res.setDrType(CS.DrType.CREDIT.getType()); + break; + default: + res.setDrType(CS.DrType.OTHER.getType()); + break; + } + }else{ + res.setDrType(CS.DrType.OTHER.getType()); + } + }else if("FAIL".equals(tranSts)){ + res.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + res.setNeedQuery(false); + } + res.setJsapiMsg(jsapiMsg); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayRefundService.java new file mode 100644 index 0000000..bb6421b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/SxfpayRefundService.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvsubMchParams; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 随行付支付 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class SxfpayRefundService extends AbstractRefundService { + + public final static String SUCCESS = "REFUNDSUC"; + + public final static String FAIL = "REFUNDFAIL"; + + public final static String ING = "REFUNDING"; + + @Override + public String getIfCode() { + return CS.IF_CODE.SXFPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + bizContent.put("mno",payOrder.getChannelMchNo()); + bizContent.put("ordNo",refundOrder.getRefundOrderId()); + bizContent.put("origOrderNo",payOrder.getPayOrderId()); + bizContent.put("amt", AmountUtil.convertCent2Dollar(bizRQ.getRefundAmount())); + bizContent.put("notifyUrl",getNotifyUrl()); + bizContent.put("refundReason",bizRQ.getRefundReason()); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(),getIfCode()); + try { + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_ORDER_REFUND, isvParams, bizContent); + String tranSts = respBizData.getString("tranSts"); + channelRetMsg.setChannelOrderId(respBizData.getString("uuid")); + channelRetMsg.setPlatformOrderNo(respBizData.getString("transactionId")); + channelRetMsg.setPlatformMchOrderNo(respBizData.getString("sxfUuid")); + channelRetMsg.setChannelErrCode(respBizData.getString("bizCode")); + channelRetMsg.setChannelErrMsg(respBizData.getString("bizMsg")); + channelRetMsg.setChannelAttach(respBizData.toString()); + switch (tranSts){ + case SUCCESS: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + case ING: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + break; + } + }catch (Exception e){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg(e.getMessage()); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), refundOrder.getIfCode()); + SxfpayIsvsubMchParams mchParams = (SxfpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getMchApplyment().getAutoConfigMchAppId(), refundOrder.getIfCode()); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + JSONObject bizContent = new JSONObject(); + // 商户订单号 + bizContent.put("mno", mchParams.getMno()); + // 退款订单号 + bizContent.put("ordNo", refundOrder.getRefundOrderId()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_REFUND_QUERY, isvParams, bizContent); + String tranSts = respBizData.getString("tranSts"); + channelRetMsg.setChannelOrderId(respBizData.getString("uuid")); + channelRetMsg.setPlatformOrderNo(respBizData.getString("transactionId")); + channelRetMsg.setPlatformMchOrderNo(respBizData.getString("sxfUuid")); + channelRetMsg.setChannelErrCode(respBizData.getString("bizCode")); + channelRetMsg.setChannelErrMsg(respBizData.getString("bizMsg")); + channelRetMsg.setChannelAttach(respBizData.toString()); + switch (tranSts){ + case SUCCESS: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + break; + case FAIL: + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + break; + } + return channelRetMsg; + } + + /** + * 退款权限 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ApplymentNotify.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ApplymentNotify.java new file mode 100644 index 0000000..0534964 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ApplymentNotify.java @@ -0,0 +1,91 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.model; + +import com.alibaba.fastjson.JSONArray; +import lombok.Data; + +import java.util.List; + +@Data +public class ApplymentNotify { + + public static final String TASK_TYPE_INCOME = "00"; + + public static final String TASK_TYPE_MODIFY = "01"; + + /** + * 进件申请ID + */ + private String applicationId; + + /** + * 商户编号 + */ + private String mno; + + /** + * 工单类型,枚举值 + * 取值范围: + * 00 入驻工单 + * 01 修改工单 + */ + private String taskType; + + /** + * 审核状态,枚举值 + * 取值范围: + * 1 入驻通过 + * 2 入驻驳回 + * 5 商户修改通过 + * 6 商户修改驳回 + */ + private String taskStatus; + + /** + * 审核结果信息 + */ + private String suggestion; + + /** + * 渠道报备信息(结构详见下方报文样例) + * childNoType 报备渠道 枚举值,取值范围: + * WX 微信 + * ZFB 支付宝 + * YL-MNO 银联普通 + * YL-QRC 银联小微 + * repoStatus 报备状态 枚举值,取值范围: + * 01 成功 + * 02 失败 + * channelId 接入方渠道号 + * childNo 渠道子商户号 + * errMessage 报备失败原因 + * aliLevel 支付宝等级 + */ + private List repoInfo; + + /** + * 收单机构商编 + * type 枚举值,取值范围: + * SXF 随行付 + * XS 新生 + */ + private JSONArray spInfo; + + /** + * 页面申请ID,进件链接模式返回 + */ + private String pageApplyId; + + @Data + public static class Repo { + + private String childNoType; + + private String childNo; + + private String repoStatus; + + private String channelId; + + private String errMessage; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqEntity.java new file mode 100644 index 0000000..6ec56d7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqEntity.java @@ -0,0 +1,59 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.model; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.util.Date; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 10:46 + */ +@Setter +@Getter +public class ReqEntity { + + public static final String DEFAULT_VERSION = "1.0"; + + public static final String DEFAULT_SIGN_TYPE = "RSA"; + + private String orgId; + + private String reqId; + + private String version; + + private String timestamp; + + private JSONObject reqData; + + private String signType; + + private String sign; + + public ReqEntity(String orgId, JSONObject reqData) { + this.orgId = orgId; + this.reqId = IdUtil.fastUUID().replace("-", ""); + this.version = DEFAULT_VERSION; + this.timestamp = DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"); + this.reqData = reqData; + this.signType = DEFAULT_SIGN_TYPE; + } + + @JSONField(serialize = false) + public String getSignContent() { + return "orgId" + "=" + orgId + "&" + + "reqData" + "=" + reqData + "&" + + "reqId" + "=" + reqId + "&" + + "signType" + "=" + signType + "&" + + "timestamp" + "=" + timestamp + "&" + + "version" + "=" + version; + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqMethod.java new file mode 100644 index 0000000..3aaf829 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/ReqMethod.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 11:52 + */ +@Data +public class ReqMethod { + + /** + * 统一请求域名 + */ + private final static String DOMAIN = "https://openapi.tianquetech.com"; + + + @Getter + @AllArgsConstructor + public enum Method{ + + WX_CERT("/merchant/realName/commitApply","微信认证"), + + WX_CERT_STATUS("/merchant/realName/queryGrantStatus","查询微信认证授权状态"), + + WX_CERT_RESULT("/merchant/realName/queryApplyInfo","微信实名认证申请结果查询接口"), + + WX_CERT_CANCEL("/merchant/realName/backApplyBill","微信实名认证申请撤销接口"), + + ALI_CERT("/merchant/alipayRealName/commitApply","支付宝实名认证申请"), + + ALI_CERT_STATUS("/merchant/alipayRealName/queryGrantStatus","支付宝实名认证状态查询"), + + ALI_CERT_RESULT("/merchant/alipayRealName/queryApplyInfo","支付宝实名认证结果查询"), + + ALI_CERT_CANCEL("/merchant/alipayRealName/backApplyBill","支付宝实名认证申请单撤销"), + + MERCHANT_INCOME("/merchant/income","商户入驻"), + + MERCHANT_INCOME_PHOTO_UPLOAD("/merchant/uploadPicture","进件图片上传"), + + MERCHANT_INFO_UPDATE("/merchant/updateMerchantInfo","商户入驻信息修改"), + + MERCHANT_INFO_MODIFY("/merchant/editMerchantInfo","商户信息修改"), + + MERCHANT_APPLY_QUERY("/merchant/queryMerchantInfo","商户申请单信息查询"), + + MERCHANT_INFO_QUERY("/merchant/merchantInfoQuery","商户信息查询通过商户号"), + + MERCHANT_AUDIT_RESULT_QUERY("/merchant/queryModifyResult","商户审核结果查询"), + + /** + * 正式环境修改商户费率信息 次日0时 生效 + */ + MERCHANT_RATE_UPDATE("/merchant/merchantSetup","商户费率信息修改"), + + MERCHANT_DETAIL_QUERY("/merchant/merchantInfoQuery","商户详情查询"), + + MERCHANT_WX_CONF("/merchant/weChatPaySet/addConf","商户微信参数配置配置APPID和支付授权目录"), + + MERCHANT_WX_CONF_QUERY("/merchant/weChatPaySet/queryConf","微信子商户支付参数查询"), + + TRADE_SCAN_PAY("/order/reverseScan","主扫付款(扫用户付款码发起支付)"), + + TRADE_JSAPI_PAY("/order/jsapiScan","被扫支付(用户扫二维码发起支付)"), + + TRADE_ORDER_REFUND("/order/refund","订单退款"), + + TRADE_REFUND_QUERY("/query/refundQuery","退款查询"), + + TRADE_ORDER_QUERY("/query/tradeQuery","交易查询"), + + TRADE_ORDER_CLOSE("/query/close","订单关闭"), + + TRADE_ORDER_CANCEL("/query/cancel","订单撤销"), + + TRADE_ACTIVE_PAY("/order/activeScan","商户生成带金额的付款码用户扫码付款"), + + OTHER_GET_WX_OPENID("/query/getSubOPenid","微信获取openid"), + + OTHER_GET_UNION_USERID("/query/getUnionInfo","获取银联用户标识"), + + + MARKET_TANSFER("/capital/fundManage/orgTransfer","营销转账"), + + MARKET_TANSFER_QUERY("/capital/fundManage/getTransferInfo","营销转账查询"), + + MARKET_TRANSFER_BATCH("/capital/fundManage/batchTransfer","批量营销转账"), + + MARKET_TRANSFER_BATCH_QUERY("/capital/fundManage/queryBatchTransfer","批量营销转账查询"), + + SETTLE_QUERY("/capital/query/querySettlement","结算查询"), + + SETTLE_BALANCE_QUERY("/capital/query/queryBalance","商户结算余额查询"), + + + CHECK_GET_FILE("/capital/fileDownload/getFileUrl","获取对账文件下载路径"), + + + + ; + + private final String method; + + private final String desc; + + } + + /** + * 获取请求接口地址 + * @param method + * @return + */ + public static String getUrl(Method method){ + return DOMAIN + method.getMethod(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/RespEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/RespEntity.java new file mode 100644 index 0000000..52727da --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/model/RespEntity.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.model; + +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Setter +@Getter +public class RespEntity implements Serializable { + + /** + * 网关响应码 + */ + private String code; + + /** + * 网关响应码描述 + */ + private String msg; + + private String orgId; + + private String reqId; + + private JSONObject respData; + + private String signType; + + /** + * 签名串 + */ + private String sign; + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliBar.java new file mode 100644 index 0000000..a524309 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliBar.java @@ -0,0 +1,59 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 随行付条码支付 + */ +@Service("sxfpayPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + SxfpayKit.setPayParams(mchAppConfigContext,bizContent,payOrder,rq); + bizContent.put("authCode", bizRQ.getAuthCode()); + bizContent.put("notifyUrl", getNotifyUrl()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_SCAN_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliJsapi.java new file mode 100644 index 0000000..891ef35 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliJsapi.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 随行付 支付宝 jsapi + * + */ +@Service("sxfpayPaymentByAliJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + this.preCheckAli(bizRQ); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + bizContent.put("payWay", "02"); + bizContent.put("notifyUrl", getNotifyUrl()); + // 买家支付宝用户ID + bizContent.put("userId", bizRQ.getBuyerUserId()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_JSAPI_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setAlipayTradeNo(channelRetMsg.getJsapiMsg().getTradeNo()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliLite.java new file mode 100644 index 0000000..e4018e5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/AliLite.java @@ -0,0 +1,65 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 支付宝 小程序 + * + */ +@Service("sxfpayPaymentByAliLiteService") //Service Name需保持全局唯一性 +public class AliLite extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + this.preCheckAli(rq); + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder, rq); + bizContent.put("payWay", "02"); + // 商户订单号 + bizContent.put("notifyUrl", getNotifyUrl()); + // 买家支付宝用户ID + bizContent.put("userId", bizRQ.getBuyerUserId()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_JSAPI_PAY, isvParams, bizContent); + initCommonResult(respBizData, channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + if (channelRetMsg.getJsapiMsg() != null) { + res.setAlipayTradeNo(channelRetMsg.getJsapiMsg().getTradeNo()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxBar.java new file mode 100644 index 0000000..7caab11 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxBar.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 随行付微信条码支付 + */ +@Service("sxfpayPaymentByWxBarService") //Service Name需保持全局唯一性 +public class WxBar extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + SxfpayKit.setPayParams(mchAppConfigContext,bizContent,payOrder,rq); + bizContent.put("authCode", bizRQ.getAuthCode()); + bizContent.put("notifyUrl", getNotifyUrl()); + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ + bizContent.put("subAppid", bizRQ.getSubAppid()); + }else{ + bizContent.put("subAppid", oauth2Params.getAppId()); + } + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_SCAN_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxJsapi.java new file mode 100644 index 0000000..3be29f0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxJsapi.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/4/15 15:37 + */ +@Slf4j +@Service("sxfpayPaymentByWxJsapiService") //Service Name需保持全局唯一性 +public class WxJsapi extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 设置请求参数 + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + bizContent.put("payWay","02"); + bizContent.put("userId", bizRQ.getOpenid()); + bizContent.put("notifyUrl",getNotifyUrl()); + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + // 商户appId + bizContent.put("subAppid", bizRQ.getSubAppid()); + }else { + // 商户appId + bizContent.put("subAppid", oauth2Params.getAppId()); + } + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_JSAPI_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxLite.java new file mode 100644 index 0000000..a47e704 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/WxLite.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:52 + */ +@Slf4j +@Service("sxfpayPaymentByWxLiteService") //Service Name需保持全局唯一性 +public class WxLite extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + // 设置请求参数 + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 商户号 + // 设置请求参数 + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder, rq); + // 商户订单号 + bizContent.put("payWay", "03"); + // 订单交易日期 + bizContent.put("userId", bizRQ.getOpenid()); + bizContent.put("notifyUrl", getNotifyUrl()); + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + // 商户appId + bizContent.put("subAppid", bizRQ.getSubAppid()); + }else { + // 商户appId + bizContent.put("subAppid", oauth2Params.getLiteAppId()); + } + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_JSAPI_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setPayInfo(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfBar.java new file mode 100644 index 0000000..79ca7f2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfBar.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRS; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 随行付 云闪付条码支付 + */ +@Service("sxfpayPaymentByYsfBarService") //Service Name需保持全局唯一性 +public class YsfBar extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + YsfBarOrderRS res = ApiResBuilder.buildSuccess(YsfBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder,rq); + bizContent.put("authCode", bizRQ.getAuthCode()); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_SCAN_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + res.setChannelRetMsg(channelRetMsg); + return res; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfJsapi.java new file mode 100644 index 0000000..5afb86b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sxfpay/payway/YsfJsapi.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.thirdparty.channel.sxfpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.sxfpay.SxfpayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 云闪付jsapi + * + */ +@Service("sxfpayPaymentByYsfJsapiService") //Service Name需保持全局唯一性 +public class YsfJsapi extends SxfpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getUserId())){ + throw new BizException("[userId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + try { + JSONObject bizContent = new JSONObject(); + SxfpayKit.setPayParams(mchAppConfigContext, bizContent, payOrder, rq); + bizContent.put("userId", bizRQ.getUserId()); + bizContent.put("notifyUrl", getNotifyUrl()); + if(StringUtils.isNotEmpty(bizRQ.getFrontUrl())){ + bizContent.put("frontUrl",bizRQ.getFrontUrl()); + } + if(StringUtils.isNotEmpty(bizRQ.getFrontFailUrl())){ + bizContent.put("frontFailUrl",bizRQ.getFrontFailUrl()); + } + SxfpayIsvParams isvParams = (SxfpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + JSONObject respBizData = SxfpayKit.reqApi(ReqMethod.Method.TRADE_JSAPI_PAY, isvParams, bizContent); + initCommonResult(respBizData,channelRetMsg); + if(channelRetMsg.getJsapiMsg() != null){ + res.setRedirectUrl(channelRetMsg.getJsapiMsg().getRedirectUrl()); + res.setPayData(JSON.toJSONString(channelRetMsg.getJsapiMsg())); + } + return res; + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferNoticeService.java new file mode 100644 index 0000000..369928f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferNoticeService.java @@ -0,0 +1,81 @@ +package com.jeequan.jeepay.thirdparty.channel.sybpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferNoticeService; +import com.jeequan.jeepay.thirdparty.channel.sybpay.kits.SybpayKits; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/* +* 收银呗 转账回调接口实现类 +* +* @author zx +* +* @date 2021/21/01 17:16 +*/ +@Service +@Slf4j +public class SybpayTransferNoticeService extends AbstractTransferNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SYBPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId) { + try { + JSONObject params = getReqParamJSON(); + log.info("【收银呗】回调通知参数:{}", params.toJSONString()); + boolean verifyResult = SybpayKits.checkSign(params); + //验签失败 + if(!verifyResult){ + log.error("【收银呗】,转账回调验签失败"); + throw ResponseException.buildText("error"); + } + String bizContent = params.getString("bizContent"); + JSONObject bizJson = SybpayKits.analysisNotify(bizContent,params.getString("check")); + String transferId = bizJson.getString("outOrderNo"); + return MutablePair.of(transferId, bizJson); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, TransferOrder transferOrder) { + try { + // 获取请求参数 + JSONObject bizContent = (JSONObject) params; + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("success"); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setResponseEntity(okResponse); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + String remark = bizContent.getString("request_remark"); + channelRetMsg.setChannelErrMsg(remark); + Integer status = bizContent.getIntValue("state"); + if(status == 1){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else if(status == 0){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if(status == 2){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return channelRetMsg; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("error"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferService.java new file mode 100644 index 0000000..a51849d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/SybpayTransferService.java @@ -0,0 +1,106 @@ +package com.jeequan.jeepay.thirdparty.channel.sybpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferService; +import com.jeequan.jeepay.thirdparty.channel.sybpay.kits.SybpayKits; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +/** + * 转账接口: 收银呗 + */ +@Slf4j +@Service +public class SybpayTransferService extends AbstractTransferService { + + @Override + public String getIfCode() { + return CS.IF_CODE.SYBPAY; + } + + @Override + public boolean isSupport(String entryType) { + // 收银呗安全发仅支持 支付宝 和 银行卡入账方式 + if(TransferOrder.ENTRY_ALIPAY_CASH.equals(entryType) || TransferOrder.ENTRY_BANK_CARD.equals(entryType)){ + return true; + } + return false; + } + + @Override + public String preCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + super.preCheck(bizRQ, transferOrder); + + if(!TransferOrder.ENTRY_ALIPAY_CASH.equals(transferOrder.getEntryType()) && !TransferOrder.ENTRY_BANK_CARD.equals(transferOrder.getEntryType())){ + throw new BizException("只支持转账到支付宝或者银行卡"); + } + //调用前查下余额 + JSONObject bizData = new JSONObject(2); + JSONObject result = SybpayKits.reqApi(SybpayKits.QUERY_BALANCE_DOMAIN,bizData); + BigDecimal balance = result.getBigDecimal("available_amount"); + BigDecimal amount = BigDecimal.valueOf(transferOrder.getAmount()).divide(BigDecimal.valueOf(100)); + if(amount.compareTo(balance) > 0){ + throw new BizException("账户余额不足,请及时充值"); + } + return null; + } + + @Override + public ChannelRetMsg transfer(TransferOrderRQ bizRQ, TransferOrder transferOrder) throws Exception { + JSONObject reqData = new JSONObject(); + reqData.put("notifyUrl",getNotifyUrl(transferOrder.getTransferId())); + reqData.put("name",transferOrder.getAccountName()); + reqData.put("outOrderNo",transferOrder.getTransferId()); + reqData.put("price", AmountUtil.convertCent2Dollar(transferOrder.getAmount())); + reqData.put("remark",transferOrder.getTransferDesc()); + reqData.put("pay_type","1"); + if(TransferOrder.ENTRY_ALIPAY_CASH.equals(transferOrder.getEntryType())){ + reqData.put("pay_type","0"); + } + String channelExtraStr = transferOrder.getChannelExtra(); + reqData.put("payee_inst_name",transferOrder.getBankName()); + reqData.put("payee_account_type","2"); + if(StringUtils.isNotEmpty(channelExtraStr)){ + JSONObject channelExtra = JSON.parseObject(channelExtraStr); + reqData.put("inst_province",channelExtra.getString("provinceName")); + reqData.put("inst_city",channelExtra.getString("cityName")); + reqData.put("inst_branch_name",channelExtra.getString("branchName")); + reqData.put("payee_account_type", MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(channelExtra.getString("settleType")) ? "1" : "2"); + } + reqData.put("account",transferOrder.getAccountNo()); + JSONObject result = SybpayKits.reqApi(SybpayKits.TRANS_DOMAIN,reqData); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + retMsg.setChannelOrderId(result.getString("order_sn")); + return retMsg; + } + + @Override + public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) { + JSONObject reqData = new JSONObject(); + reqData.put("order_sn",transferOrder.getChannelOrderNo()); + JSONObject result = SybpayKits.reqApi(SybpayKits.TRANS_QUERY_DOMAIN,reqData); + int state = result.getIntValue("state"); + if(state == 0 || state == 3){ + return ChannelRetMsg.waiting(); + } + if (state == 1){ + return ChannelRetMsg.confirmSuccess(result.getString("order_sn")); + } + if (state == 2 || state == 4){ + return ChannelRetMsg.confirmFail(result.getString("state"),result.getString("request_msg")); + } + return ChannelRetMsg.waiting(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/kits/SybpayKits.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/kits/SybpayKits.java new file mode 100644 index 0000000..9b7f3e9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/sybpay/kits/SybpayKits.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.thirdparty.channel.sybpay.kits; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SignUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.crypto.symmetric.AES; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.xml.bind.DatatypeConverter; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +/** + * TODO + * + * @author crystal + * @date 2024/1/26 18:24 + */ +@Slf4j +public class SybpayKits { + + public static final String TRANS_DOMAIN = "http://anquanfapay.shouyinbei.com/api/v1/transfer"; + + public static final String TRANS_QUERY_DOMAIN = "http://anquanfapay.shouyinbei.com/api/v1/queryOrder"; + + public static final String QUERY_BALANCE_DOMAIN = "http://anquanfapay.shouyinbei.com/api/v1/queryBalance"; + + public static final String account_id = "50"; + + public static final String mobile = "15062443898"; + + public static final String SUCCESS_CODE = "1"; + + public static final String BIZ_SUCCESS_CODE = "10000"; + + public static final String PUB_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0DNaYHTLA6Y83miQaBggGjpVdSycumtbg6vq9EadM2gW5IPZ74DzQaw61K3hUnquFAcB2OYE0EDvnQYGLnabPPvJQ+/neZefe75IZ84kamxb6LFvi2MjFAr+AB2a+pPas0h3EOdQs/B/N6SIYZzGef3inEWxxi+/qzccIgyF5hVECadxm6qgpnyqfVW8HLCBjSjc74GPZ8xC/AovDxcycdUVcDrF0AHekkMxA8DkcWGcQ+IGFqjs0wPB7xlfcpG+1n1NWFUJXZX7tJpI8yv7GhxYmMGjHlmkEDijPflwqRGVQRrV+NyuoJCtlDExdfj8Z3sMlQ/rCeacsh98ONdKMwIDAQAB"; + + public static final String PRI_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaj1TK3w2h5lpIikqkTbxgxgqQcbjb3s6Sv8yhJ5i2qbPbcgy8h2W68+8pbtvDleRTLu9zP/BPjXcOF+kKPa8gOLFOdRtpzOQp3KlXxDTzsLC329bnyAwccr0O6rEmMj8hrPUznXXcA6jXYxLo2ICgu457ALfpwEz6qtUOYbRQSssVX+W5UPkqgYR+BnMGeCXvVoNA2k4SYixo1DXuI6IjZki3OuaX87BBoRiW2bIu3MxcgaYkq08PUeZtdOuJqI7I87vNXKO0Xu7JcA4cWQnKzjuUC9zTRj0ETDsxyQDsRmvJmJ9SUI33c0Q1v3OGnyko7TNVBPNKVLRgDQI9oKTvAgMBAAECggEAMVWk9CikmlQD53m0/6MMiTtNrfOO1SfWekMclygjd9LNZTOPWzJAx58LbQdEwLZ8rgyiRABZvZrjMK1zJmCwILHX7ro0qN3Myovzxd8MI+j3T4itnUhejUoWjMdfClkpi59AmVwefb7xSucF5ysMS8HyZdLB4awPJkgXP8LyIlpt+GHS6f5Mg/mkCpoG48FNdpjuPD9BTnEIHuZTNO5FpCrXbmuUAhoXjQHTOP0aDKYxYlMDS7XFoMcvjKI5gCaIWDmmmvmMaKngFHSETGQ6XQjIQ4ediUMAd5DHrzDqCi/WCGGbSvBf7z9TRKFW6shrYDxkRgReliFIrhffJ/M64QKBgQDXmEX2vH+Vq+bjSEti5fZ/XLEwQZ+GkcmyYr/GZcZMdhfSDoxc0boH9KQMhXFtQMlvmLIgrPKOs7Mb6nPP5UPyRhCytwso8MnlyHFQrtqamKyEMMoLtjJmwD2vGBxR5ugHXnnQFc0v9aurw8/mdr2M/dtpwALVNSloHCo0IeF13wKBgQC3hr9CzkA+WY8EFl1dhU5Md9Dkc61nImLFVdPLgggnR0/Qh3sZFNngmuayxZ2KFpEwlJ4GTA6LriEFOvbA1YCeC0BZkRW0vldJd8qJetnaUj3Y3b7ZMSQEvNPT7G/PhePtV9m1E+mgdlDfF/5dOTQs+xzknC8VZmqqvEYDTskS8QKBgQCTa3cjwT8IjBQEA/IwfQixjCNI2QaJEPU3OljiA8O1kua05ufJrEsll335ZeHqj+ttmJ7swvXU6EGn7Agm9yEf8BMI8Sr7YrLbodUCE549KfqFJYtyuLH8GqXTLYxn4Jl2OH7Y759vlPA/MlTdxQHV/9vhkr8dJQ3cN64QGb6+RwKBgHq3gUB8hXyrifPjuH6GWrrLC0UXDIX/+ieVok9cHXOWPYpkbS1yQdXr/gLgHN1vBZqEZb40MS25O58xtDlxCdWkFF1PpEH9XIRls2qGWRGhGHXgoHK+ZyU71jDI0mLjVmsn6Q0pyXhgZOcoNg/D5l2Fc+ZxgRJAL2cHCZHAprchAoGBAJRehV/N7zSJreY4+tf8lshKcoWuX9rKOakRLEK3UIHQwKBQj7x/CNvPbdslJ6kCgAhhLdztudWFgrcZT2eNs59d2OaT2lIhjzVdf9SPhQkrHoeNEeuO1gsIhWkgakt7wjGU5EsuwN00LCYaw+EZLhIbbpANP5Q44pgj1ebR1I3i"; + + /** + * 发起请求 + * @param url + * @param bizData + * @return + */ + public static JSONObject reqApi(String url, JSONObject bizData) { + bizData.put("mobile",mobile); + bizData.put("account_id",account_id); + bizData.put("pay_pwd",mobile); + JSONObject reqData = new JSONObject(); + reqData.put("requestId", StringKit.getUUID()); + reqData.put("timestamp", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT)); + reqData.put("bizContent",bizData.toString()); + log.info("【安全发】接口加密前参数:{}",reqData); + initSign(reqData); + log.info("【安全发】接口请求参数:{}",reqData); + String response = HttpUtil.post(url, reqData.toString()); + log.info("【安全发】接口返回参数:{}",response); + if(StringUtils.isEmpty(response)){ + throw new BizException("转账接口异常"); + } + JSONObject result = JSON.parseObject(response); + if(!SUCCESS_CODE.equals(result.getString("code"))){ + throw new BizException(result.getString("msg")); + } + return result.getJSONObject("data"); + } + + /** + * 初始化SIGN + * @param reqData + */ + private static void initSign(JSONObject reqData) { + String bizContent = reqData.getString("bizContent"); + String randomKey = RandomUtil.randomString(16); + AES aes = SecureUtil.aes(randomKey.getBytes(StandardCharsets.UTF_8)); + if (!bizContent.isEmpty()) { + reqData.put("bizContent",aes.encryptBase64(bizContent)); + } + RSA rsa = SecureUtil.rsa(PRI_KEY,PUB_KEY); + reqData.put("check",rsa.encryptBase64(randomKey, KeyType.PublicKey)); + String signContent = "bizContent=" + reqData.getString("bizContent") + "&check="+reqData.getString("check") + "&requestId="+reqData.getString("requestId") + "×tamp="+reqData.getString("timestamp"); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, PRI_KEY,PUB_KEY); + byte[] signByte = sign.sign(signContent); + reqData.put("sign",DatatypeConverter.printBase64Binary(signByte)); + } + + /** + * 验证签名 + * @param params + * @return + */ + public static Boolean checkSign(JSONObject params) { + Sign signUtil = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, PUB_KEY); + String signContent = "bizContent=" + params.getString("bizContent") + "&check="+params.getString("check") + "&requestId="+params.getString("requestId") + "×tamp="+params.getString("timestamp"); + return signUtil.verify(signContent.getBytes(StandardCharsets.UTF_8), DatatypeConverter.parseBase64Binary(params.getString("sign"))); + } + + /** + * 解析回调参数 + * @param bizContent + * @param check + * @return + */ + public static JSONObject analysisNotify(String bizContent,String check) { + RSA rsa = SecureUtil.rsa(PRI_KEY,PUB_KEY); + String randomKey = rsa.decryptStr(check, KeyType.PrivateKey); + AES aes = SecureUtil.aes(randomKey.getBytes(StandardCharsets.UTF_8)); + return JSON.parseObject(aes.decryptStr(bizContent)); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayBillDownloadService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayBillDownloadService.java new file mode 100644 index 0000000..e1b6540 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayBillDownloadService.java @@ -0,0 +1,281 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.csv.CsvData; +import cn.hutool.core.text.csv.CsvRow; +import cn.hutool.core.text.csv.CsvUtil; +import com.github.binarywang.wxpay.bean.request.WxPayApplyTradeBillV3Request; +import com.github.binarywang.wxpay.bean.request.WxPayDownloadBillRequest; +import com.github.binarywang.wxpay.bean.result.WxPayApplyBillV3Result; +import com.github.binarywang.wxpay.bean.result.WxPayBillInfo; +import com.github.binarywang.wxpay.bean.result.WxPayBillResult; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.CheckBatch; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.bill.ChannelBill; +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 com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.CheckChannelBill; +import com.jeequan.jeepay.thirdparty.channel.AbstractBillDownloadService; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/* +* 微信 对账单下载 +* +* @author zx +* +* @date 2021/6/8 17:20 +*/ +@Slf4j +@Service +public class WxpayBillDownloadService extends AbstractBillDownloadService { + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public ChannelBillRS convertStandardBill(ChannelBillRQ channelBillRQ, MchAppConfigContext mchAppConfigContext, Date billDate, String ifCode){ + + String logPrefix = "【微信对账单下载】"; + + WxServiceWrapper wxServiceWrapper; + + // true-服务商模式 + boolean isvType = ChannelBillRQ.INFO_TYPE_ISV.equals(channelBillRQ.getInfoType()); + if (isvType) { + WxpayIsvParams wxpayIsvParams = (WxpayIsvParams) channelBillRQ.getIsvParams(); + wxServiceWrapper = WxServiceWrapper.buildWxServiceWrapper(wxpayIsvParams, null); + }else { + WxpayNormalMchParams wxpayNormalMchParams = (WxpayNormalMchParams) channelBillRQ.getNormalMchParams(); + wxServiceWrapper = WxServiceWrapper.buildWxServiceWrapper(wxpayNormalMchParams, null); + } + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 渠道商户号 + String channelMchNo = channelBillRQ.getChannelMchNo(); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { // V2 + return convertStandardBillV2(ifCode, wxPayService, isvType, channelMchNo, billDate, logPrefix); + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { // V3 + return convertStandardBillV3(ifCode, wxPayService, isvType, channelMchNo, billDate, logPrefix); + }else { + throw new BizException("请选择微信V2或V3模式!"); + } + } + + private ChannelBillRS convertStandardBillV2(String ifCode, WxPayService wxPayService, boolean isvsubMch, String channelMchNo, Date billDate, String logPrefix) { + ChannelBillRS channelBillRes = new ChannelBillRS(); + + WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); + request.setBillDate(DateUtil.format(billDate, DatePattern.PURE_DATE_PATTERN)); + request.setBillType("ALL"); + request.setTarType(WxPayConstants.TarType.GZIP); + + try { + // 微信List账单 + WxPayBillResult wxPayBillResult = wxPayService.downloadBill(request); + List billInfoList = wxPayBillResult.getBillInfoList(); + + // 上传oss + byte[] bytes = wxPayService.postForBytes(wxPayService.getPayBaseUrl() + "/pay/downloadbill", request.toXML(), false); + String url = upload2Oss(getIfCode(), channelMchNo, billDate, ".gzip", new ByteArrayInputStream(bytes)); + /*ByteArrayOutputStream out = new ByteArrayOutputStream(); + ExcelUtil.getBigWriter().write(billInfoList).flush(out); + String url = upload2Oss(getIfCode(), channelMchNo, billDate, ".csv", new ByteArrayInputStream(out.toByteArray()));*/ + + // 生成附带对账文件下载地址的解析成功的批次 + CheckBatch checkBatch = genReleaseSuccessCheckBatch(ifCode, billDate, channelMchNo, url); + // 渠道账单列表 + List channelBillList = new ArrayList<>(); + // 渠道总退款笔数 + int channelTotalRefundCount = 0; + + for (WxPayBillInfo billInfo: billInfoList){ + ChannelBill channelBill = new ChannelBill(); + channelBill.setBatchNo(checkBatch.getBatchNo()); + channelBill.setBillDate(billDate); + channelBill.setIfCode(getIfCode()); + channelBill.setChannelMchNo(channelMchNo); + channelBill.setChannelOrderNo(billInfo.getTransactionId()); + channelBill.setChannelSuccessAt(DateUtil.parseDateTime(billInfo.getTradeTime())); + channelBill.setChannelUser(billInfo.getOpenId()); + // 特约商户 覆写渠道子商户号 + if (isvsubMch) { + channelBill.setChannelMchNo(billInfo.getSubMchId()); + } + + if (StringUtils.equals(billInfo.getTradeState(), "SUCCESS")) { // 支付 + channelBill.setOrderId(billInfo.getOutTradeNo()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_PAY); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(billInfo.getTotalFee())) + Math.abs(AmountUtil.convertDollar2CentLong(billInfo.getCouponFee()))); + channelBill.setChannelFeeAmount(Math.abs(AmountUtil.convertDollar2CentLong(billInfo.getPoundage()))); + channelBill.setChannelState((byte) 2); + + }else if (StringUtils.equals(billInfo.getTradeState(), "REFUND")) { // 退款 + channelBill.setOrderId(billInfo.getOutRefundNo()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(billInfo.getAppliedRefundAmount()))); + + String refundState = billInfo.getRefundState(); + if (StringUtils.equals(refundState, "SUCCESS")) { + channelBill.setChannelState((byte) 5); + } + channelTotalRefundCount++; + }else { + log.error("{}账单类型错误!", logPrefix); + continue; + } + channelBillList.add(channelBill); + } + + checkBatch.setChannelTotalCount(Integer.parseInt(wxPayBillResult.getTotalRecord()) - channelTotalRefundCount); + checkBatch.setChannelTotalRefundCount(channelTotalRefundCount); + checkBatch.setChannelTotalAmount(Math.abs(AmountUtil.convertDollar2CentLong(wxPayBillResult.getTotalFee())) + Math.abs(AmountUtil.convertDollar2CentLong(wxPayBillResult.getTotalCouponFee()))); + checkBatch.setChannelTotalRefundAmount(Math.abs(AmountUtil.convertDollar2CentLong(wxPayBillResult.getTotalRefundFee()))); + checkBatch.setChannelTotalFee(Math.abs(AmountUtil.convertDollar2CentLong(wxPayBillResult.getTotalPoundageFee()))); + + channelBillRes.setCheckBatch(checkBatch); + channelBillRes.setChannelBillList(channelBillList); + + return channelBillRes; + } catch (WxPayException e) { + log.error("{}, 解析对账文件失败,", logPrefix, e); + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage())); + return channelBillRes; + } + } + + private ChannelBillRS convertStandardBillV3(String ifCode, WxPayService wxPayService, boolean isvsubMch, String channelMchNo, Date billDate, String logPrefix) { + ChannelBillRS channelBillRes = new ChannelBillRS(); + + WxPayApplyTradeBillV3Request request = new WxPayApplyTradeBillV3Request(); + request.setBillDate(DateUtil.formatDate(billDate)); + request.setBillType("ALL"); + + // 下载地址 + String downloadUrl; + try { + // 申请对账单 + WxPayApplyBillV3Result wxPayApplyBillV3Result = wxPayService.applyTradeBill(request); + downloadUrl = wxPayApplyBillV3Result.getDownloadUrl(); + log.info("{},微信商户号={},下载成功", logPrefix, channelMchNo); + }catch (Exception e) { + log.error("{},微信商户号={},申请对账文件失败", logPrefix, channelMchNo, e); + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage())); + return channelBillRes; + } + + if (StringUtils.isBlank(downloadUrl)) { + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, "下载地址为空!")); + return channelBillRes; + } + + // 解析数据 + try { + InputStream inputStream = wxPayService.downloadBill(downloadUrl); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + IoUtil.copy(inputStream, byteArrayOutputStream); + + // 上传oss + String url = upload2Oss(getIfCode(), channelMchNo, billDate, ".csv", IoUtil.toStream(byteArrayOutputStream)); + // 生成附带对账文件下载地址的解析成功的批次 + CheckBatch checkBatch = genReleaseSuccessCheckBatch(ifCode, billDate, channelMchNo, url); + // 渠道账单列表 + List channelBillList = new ArrayList<>(); + // 渠道总退款笔数 + int channelTotalRefundCount = 0; + + // 读取对账单 csv文件 + CsvData data = CsvUtil.getReader(new InputStreamReader(IoUtil.toStream(byteArrayOutputStream))).read(); + List rows = data.getRows(); + + // 遍历行 + if (rows.size() > 2) { + for (int i = 1; i < rows.size() - 2; i++) { + CsvRow csvRow = rows.get(i); + // getRawList返回一个List列表,列表的每一项为CSV中的一个单元格 + List rawList = csvRow.getRawList(); + + if (rawList.size() > 25) { + ChannelBill channelBill = new ChannelBill(); + channelBill.setBatchNo(checkBatch.getBatchNo()); + channelBill.setBillDate(billDate); + channelBill.setIfCode(getIfCode()); + channelBill.setChannelMchNo(channelMchNo); + channelBill.setChannelOrderNo(rawList.get(5).substring(1).trim()); + channelBill.setChannelFeeAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(22).substring(1).trim()))); + channelBill.setChannelSuccessAt(DateUtil.parseDate(rawList.get(0).substring(1).trim())); + channelBill.setChannelUser(rawList.get(7).substring(1).trim()); + // 特约商户 覆写渠道子商户号 + if (isvsubMch) { + channelBill.setChannelMchNo(rawList.get(3).substring(1).trim()); + } + + if (StringUtils.equals(rawList.get(9).substring(1).trim(), "SUCCESS")) { // 支付 + channelBill.setOrderId(rawList.get(6).substring(1).trim()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_PAY); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(12).substring(1).trim())) + Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(13).substring(1).trim()))); + channelBill.setChannelState((byte) 2); + + }else if (StringUtils.equals(rawList.get(9).substring(1).trim(), "REFUND")) { // 退款 + channelBill.setOrderId(rawList.get(15).substring(1).trim()); + channelBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND); + channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(25).substring(1).trim()))); + + String refundState = rawList.get(19).substring(1).trim(); + if (StringUtils.equals(refundState, "SUCCESS")) { + channelBill.setChannelState((byte) 5); + } + channelTotalRefundCount++; + }else { + log.error("{}账单类型错误!", logPrefix); + continue; + } + + channelBillList.add(channelBill); + } + } + + List rawList = rows.get(rows.size() - 1).getRawList(); + checkBatch.setChannelTotalCount(Integer.valueOf(rawList.get(0).substring(1).trim())); + checkBatch.setChannelTotalRefundCount(channelTotalRefundCount); + checkBatch.setChannelTotalAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(1).substring(1).trim())) + Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(3).substring(1).trim()))); + checkBatch.setChannelTotalRefundAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(6).substring(1).trim()))); + checkBatch.setChannelTotalFee(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(4).substring(1).trim()))); + } + + channelBillRes.setCheckBatch(checkBatch); + channelBillRes.setChannelBillList(channelBillList); + + return channelBillRes; + + } catch (WxPayException e) { + log.error("{},解析对账文件失败,微信商户号:{}", logPrefix, channelMchNo, e); + channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage())); + return channelBillRes; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelNoticeService.java new file mode 100644 index 0000000..9c5d575 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelNoticeService.java @@ -0,0 +1,243 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.notify.SignatureHeader; +import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier; +import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner; +import com.github.binarywang.wxpay.v3.auth.WxPayCredentials; +import com.github.binarywang.wxpay.v3.util.PemUtils; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.service.impl.PayOrderService; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.math.BigDecimal; +import java.security.PrivateKey; + +/* +* 微信回调 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Service +@Slf4j +public class WxpayChannelNoticeService extends AbstractChannelNoticeService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Autowired private PayOrderService payOrderService; + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + if(StringUtils.isNotBlank(urlOrderId)){ // V3接口回调 + + // 获取订单信息 + PayOrder payOrder = payOrderService.getById(urlOrderId); + if(payOrder == null){ + throw new BizException("订单不存在"); + } + + //获取支付参数 (缓存数据) 和 商户信息 + MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(payOrder.getMchNo(), payOrder.getAppId(),payOrder.getMchExtNo()); + if(mchAppConfigContext == null){ + throw new BizException("获取商户信息失败"); + } + + // 验签 && 获取订单回调数据 + WxPayOrderNotifyV3Result.DecryptNotifyResult result = parseOrderNotifyV3Result(request, mchAppConfigContext); + + return MutablePair.of(result.getOutTradeNo(), result); + + } else { // V2接口回调 + String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); + log.error("微信V2支付通知数据:{}", xmlResult); + + if(StringUtils.isEmpty(xmlResult)) { + return null; + } + + WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult); + String payOrderId = result.getOutTradeNo(); + return MutablePair.of(payOrderId, result); + } + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + ChannelRetMsg channelResult = new ChannelRetMsg(); + channelResult.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + channelResult.setChannelBizData(JSON.parseObject(JSON.toJSONString(params))); + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { // V2 + // 获取回调参数 + WxPayOrderNotifyResult result = (WxPayOrderNotifyResult) params; + + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 验证参数 + verifyWxPayParams(wxPayService, result, payOrder); + + channelResult.setChannelOrderId(result.getTransactionId()); //渠道订单号 + channelResult.setPlatformOrderNo(result.getTransactionId()); + channelResult.setPlatformMchOrderNo(payOrder.getPayOrderId()); + channelResult.setChannelUserId(result.getOpenid()); //支付用户ID + channelResult.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelResult.setResponseEntity(textResp(WxPayNotifyResponse.successResp("OK"))); + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { // V3 + // 获取回调参数 + WxPayOrderNotifyV3Result.DecryptNotifyResult result = (WxPayOrderNotifyV3Result.DecryptNotifyResult) params; + + // 验证参数 + verifyWxPayParams(result, payOrder); + + String channelState = result.getTradeState(); + if ("SUCCESS".equals(channelState)) { + channelResult.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else if("CLOSED".equals(channelState) + || "REVOKED".equals(channelState) + || "PAYERROR".equals(channelState)){ //CLOSED—已关闭, REVOKED—已撤销, PAYERROR--支付失败 + channelResult.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); //支付失败 + } + + channelResult.setChannelOrderId(result.getTransactionId()); //渠道订单号 + channelResult.setPlatformOrderNo(result.getTransactionId()); + channelResult.setPlatformMchOrderNo(payOrder.getPayOrderId()); + WxPayOrderNotifyV3Result.Payer payer = result.getPayer(); + if (payer != null) { + channelResult.setChannelUserId(payer.getOpenid()); //支付用户ID + } + + JSONObject resJSON = new JSONObject(); + resJSON.put("code", "SUCCESS"); + resJSON.put("message", "成功"); + + ResponseEntity okResponse = jsonResp(resJSON); + channelResult.setResponseEntity(okResponse); //响应数据 + + }else { + throw ResponseException.buildText("API_VERSION ERROR"); + } + + return channelResult; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * V2接口验证微信支付通知参数 + * @return + */ + public void verifyWxPayParams(WxPayService wxPayService, WxPayOrderNotifyResult result, PayOrder payOrder) { + + try { + result.checkResult(wxPayService, WxPayConstants.SignType.MD5, true); + + // 核对金额 + Integer total_fee = result.getTotalFee(); // 总金额 + long wxPayAmt = new BigDecimal(total_fee).longValue(); + long dbPayAmt = payOrder.getAmount().longValue(); + if (dbPayAmt != wxPayAmt) { + throw ResponseException.buildText("AMOUNT ERROR"); + } + } catch (Exception e) { + throw ResponseException.buildText("ERROR"); + } + } + + /** + * V3校验通知签名 + * @param request 请求信息 + * @param mchAppConfigContext 商户配置 + * @return true:校验通过 false:校验不通过 + */ + private WxPayOrderNotifyV3Result.DecryptNotifyResult parseOrderNotifyV3Result(HttpServletRequest request, MchAppConfigContext mchAppConfigContext) throws Exception { + SignatureHeader header = new SignatureHeader(); + header.setTimeStamp(request.getHeader("Wechatpay-Timestamp")); + header.setNonce(request.getHeader("Wechatpay-Nonce")); + header.setSerial(request.getHeader("Wechatpay-Serial")); + header.setSignature(request.getHeader("Wechatpay-Signature")); + + // 获取加密信息 + String params = getReqParamFromBody(); + + log.info("\n【请求头信息】:{}\n【加密数据】:{}", header.toString(), params); + + WxPayService wxPayService = configContextQueryService.getWxServiceWrapper(mchAppConfigContext).getWxPayService(); + WxPayConfig wxPayConfig = wxPayService.getConfig(); + // 自动获取微信平台证书 + FileInputStream fis = new FileInputStream(wxPayConfig.getPrivateKeyPath()); + PrivateKey privateKey = PemUtils.loadPrivateKey(fis); + fis.close(); + AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( + new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)), + wxPayConfig.getApiV3Key().getBytes("utf-8")); + wxPayConfig.setVerifier(verifier); + wxPayService.setConfig(wxPayConfig); + + WxPayOrderNotifyV3Result result = wxPayService.parseOrderNotifyV3Result(params, header); + + return result.getResult(); + } + + /** + * V3接口验证微信支付通知参数 + * @return + */ + public void verifyWxPayParams(WxPayOrderNotifyV3Result.DecryptNotifyResult result, PayOrder payOrder) { + + try { + // 核对金额 + Integer total_fee = result.getAmount().getTotal(); // 总金额 + long wxPayAmt = new BigDecimal(total_fee).longValue(); + long dbPayAmt = payOrder.getAmount().longValue(); + if (dbPayAmt != wxPayAmt) { + throw ResponseException.buildText("AMOUNT ERROR"); + } + } catch (Exception e) { + throw ResponseException.buildText("ERROR"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelRefundNoticeService.java new file mode 100644 index 0000000..f366450 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayChannelRefundNoticeService.java @@ -0,0 +1,228 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.notify.SignatureHeader; +import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier; +import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner; +import com.github.binarywang.wxpay.v3.auth.WxPayCredentials; +import com.github.binarywang.wxpay.v3.util.PemUtils; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.service.impl.RefundOrderService; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.math.BigDecimal; +import java.security.PrivateKey; + +/* + * 微信 退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2022/1/26 15:33 + */ +@Service +@Slf4j +public class WxpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Autowired private RefundOrderService refundOrderService; + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + + // 获取订单信息 + RefundOrder refundOrder = refundOrderService.getById(urlOrderId); + if(refundOrder == null){ + throw new BizException("订单不存在"); + } + + //获取支付参数 (缓存数据) 和 商户信息 + MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(refundOrder.getMchNo(), refundOrder.getAppId(),refundOrder.getMchExtNo()); + if(mchAppConfigContext == null){ + throw new BizException("获取商户信息失败"); + } + String apiVersion = ""; // 接口类型 + String wxKey = ""; // 微信私钥 + Byte mchType = mchAppConfigContext.getMchType(); + if (CS.MCH_TYPE_NORMAL == mchType) { + WxpayNormalMchParams normalMchParams = (WxpayNormalMchParams) configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + apiVersion = normalMchParams.getApiVersion(); + wxKey = CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)?normalMchParams.getKey():normalMchParams.getApiV3Key(); + }else if (CS.MCH_TYPE_ISVSUB == mchType) { + WxpayIsvParams wxpayIsvParams = (WxpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + apiVersion = wxpayIsvParams.getApiVersion(); + wxKey = CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)?wxpayIsvParams.getKey():wxpayIsvParams.getApiV3Key(); + }else { + throw new BizException("商户类型错误"); + } + + if(CS.PAY_IF_VERSION.WX_V3.equals(apiVersion)){ // V3接口回调 + // 验签 && 获取订单回调数据 + WxPayRefundNotifyV3Result.DecryptNotifyResult result = parseOrderNotifyV3Result(request, mchAppConfigContext); + return MutablePair.of(urlOrderId, result); + + } else if (CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)){ // V2接口回调 + String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); + if(StringUtils.isEmpty(xmlResult)) { + return null; + } + WxPayRefundNotifyResult result = WxPayRefundNotifyResult.fromXML(xmlResult, wxKey); + return MutablePair.of(urlOrderId, result.getReqInfo()); + } + return null; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + ChannelRetMsg result = new ChannelRetMsg(); + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + WxPayRefundNotifyV3Result.DecryptNotifyResult notifyResult = (WxPayRefundNotifyV3Result.DecryptNotifyResult) params; + // 验证参数 + verifyWxPay3Params(notifyResult, refundOrder); + String refundStatus = notifyResult.getRefundStatus(); + if ("SUCCESS".equals(refundStatus)) { + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else { //CHANGE—退款异常, REFUNDCLOSE—退款关闭 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); //退款失败 + } + result.setChannelOrderId(notifyResult.getTransactionId()); // 渠道订单号 + + JSONObject resJSON = new JSONObject(); + resJSON.put("code", "SUCCESS"); + resJSON.put("message", "成功"); + + ResponseEntity okResponse = jsonResp(resJSON); + result.setResponseEntity(okResponse); //响应数据 + }else if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { + // 获取回调参数 + WxPayRefundNotifyResult.ReqInfo notifyResult = (WxPayRefundNotifyResult.ReqInfo) params; + // 验证参数 + verifyWxPay2Params(notifyResult, refundOrder); + + result.setChannelOrderId(notifyResult.getTransactionId()); //渠道订单号 + if ("SUCCESS".equals(notifyResult.getRefundStatus())) { + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else { //CHANGE—退款异常, REFUNDCLOSE—退款关闭 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); //退款失败 + } + result.setResponseEntity(textResp(WxPayNotifyResponse.successResp("OK"))); + }else { + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); //退款失败 + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * V3校验通知签名 + * @param request 请求信息 + * @param mchAppConfigContext 商户配置 + * @return true:校验通过 false:校验不通过 + */ + private WxPayRefundNotifyV3Result.DecryptNotifyResult parseOrderNotifyV3Result(HttpServletRequest request, MchAppConfigContext mchAppConfigContext) throws Exception { + SignatureHeader header = new SignatureHeader(); + header.setTimeStamp(request.getHeader("Wechatpay-Timestamp")); + header.setNonce(request.getHeader("Wechatpay-Nonce")); + header.setSerial(request.getHeader("Wechatpay-Serial")); + header.setSignature(request.getHeader("Wechatpay-Signature")); + + // 获取加密信息 + String params = getReqParamFromBody(); + + log.info("\n【请求头信息】:{}\n【加密数据】:{}", header.toString(), params); + + WxPayService wxPayService = configContextQueryService.getWxServiceWrapper(mchAppConfigContext).getWxPayService(); + WxPayConfig wxPayConfig = wxPayService.getConfig(); + // 自动获取微信平台证书 + FileInputStream fis = new FileInputStream(wxPayConfig.getPrivateKeyPath()); + PrivateKey privateKey = PemUtils.loadPrivateKey(fis); + fis.close(); + AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( + new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)), + wxPayConfig.getApiV3Key().getBytes("utf-8")); + wxPayConfig.setVerifier(verifier); + wxPayService.setConfig(wxPayConfig); + + WxPayRefundNotifyV3Result result = wxPayService.parseRefundNotifyV3Result(params, header); + + return result.getResult(); + } + + /** + * V3接口验证微信支付通知参数 + * @return + */ + public void verifyWxPay3Params(WxPayRefundNotifyV3Result.DecryptNotifyResult result, RefundOrder refundOrder) { + + try { + // 核对金额 + long wxPayAmt = result.getAmount().getRefund(); + long dbPayAmt = refundOrder.getRefundAmount(); + if (dbPayAmt != wxPayAmt) { + throw ResponseException.buildText("AMOUNT ERROR"); + } + } catch (Exception e) { + throw ResponseException.buildText("ERROR"); + } + } + + /** + * V2接口验证微信支付通知参数 + * @return + */ + public void verifyWxPay2Params(WxPayRefundNotifyResult.ReqInfo result, RefundOrder refundOrder) { + + try { + // 核对金额 + Integer total_fee = result.getRefundFee(); // 退款金额 + long wxPayAmt = new BigDecimal(total_fee).longValue(); + long dbPayAmt = refundOrder.getRefundAmount().longValue(); + if (dbPayAmt != wxPayAmt) { + throw ResponseException.buildText("AMOUNT ERROR"); + } + } catch (Exception e) { + throw ResponseException.buildText("ERROR"); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayDivisionService.java new file mode 100644 index 0000000..0db729d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayDivisionService.java @@ -0,0 +1,384 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.profitsharing.*; +import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReceiver; +import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingUnfreezeRequest; +import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingUnfreezeResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** +* 分账接口: 微信官方 +* +* @author terrfly +* +* @date 2021/8/22 09:05 +*/ +@Slf4j +@Service +public class WxpayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + + try { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + ProfitSharingReceiverRequest request = new ProfitSharingReceiverRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, request); + + JSONObject receiverJSON = new JSONObject(); + + // 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID, 不支持 PERSONAL_SUB_OPENID ) + receiverJSON.put("type", mchDivisionReceiver.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID"); + receiverJSON.put("account", mchDivisionReceiver.getAccNo()); + receiverJSON.put("name", mchDivisionReceiver.getAccName()); + receiverJSON.put("relation_type", mchDivisionReceiver.getRelationType()); + receiverJSON.put("custom_relation", mchDivisionReceiver.getRelationTypeName()); + request.setReceiver(receiverJSON.toJSONString()); + + ProfitSharingReceiverResult profitSharingReceiverResult = + wxServiceWrapper.getWxPayService().getProfitSharingService().addReceiver(request); + + // 明确成功 + return ChannelRetMsg.confirmSuccess(null); + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + + ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver(); + + profitSharingReceiver.setType(mchDivisionReceiver.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID"); + profitSharingReceiver.setAccount(mchDivisionReceiver.getAccNo()); + profitSharingReceiver.setName(mchDivisionReceiver.getAccName()); + profitSharingReceiver.setRelationType(mchDivisionReceiver.getRelationType()); + profitSharingReceiver.setCustomRelation(mchDivisionReceiver.getRelationTypeName()); + + profitSharingReceiver.setAppid(WxpayKit.getWxPayConfig(wxServiceWrapper).getAppId()); + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + profitSharingReceiver.setSubMchId(isvsubMchParams.getSubMchId()); + } + + ProfitSharingReceiver receiver = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().addProfitSharingReceiver(profitSharingReceiver); + + // 明确成功 + return ChannelRetMsg.confirmSuccess(null); + } else { + return ChannelRetMsg.sysError("请选择微信V2或V3模式"); + } + + } catch (WxPayException wxPayException) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException); + return channelRetMsg; + + } catch (Exception e) { + + log.error("请求微信绑定分账接口异常!", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg("系统异常:" + e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + + try { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + ProfitSharingRequest request = new ProfitSharingRequest(); + request.setTransactionId(payOrder.getChannelOrderNo()); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, request); + + if(recordList.isEmpty()){ + request.setOutOrderNo(SeqKit.genDivisionBatchId()); // 随机生成一个订单号 + }else{ + request.setOutOrderNo(recordList.get(0).getBatchOrderId()); //取到批次号 + } + + JSONArray receiverJSONArray = new JSONArray(); + + for (int i = 0; i < recordList.size(); i++) { + + PayOrderDivisionRecord record = recordList.get(i); + if(record.getCalDivisionAmount() <= 0){ + continue; + } + + JSONObject receiverJSON = new JSONObject(); + // 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID, 不支持 PERSONAL_SUB_OPENID ) + receiverJSON.put("type", record.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID"); + receiverJSON.put("account", record.getAccNo()); + receiverJSON.put("amount", record.getCalDivisionAmount()); + receiverJSON.put("description", record.getPayOrderId() + "分账"); + receiverJSONArray.add(receiverJSON); + } + + //不存在接收账号时,订单完结(解除冻结金额) + if(receiverJSONArray.isEmpty()){ + return ChannelRetMsg.confirmSuccess(this.divisionFinish(payOrder, mchAppConfigContext)); + } + + request.setReceivers(receiverJSONArray.toJSONString()); + + ProfitSharingResult profitSharingResult = wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharing(request); + return ChannelRetMsg.confirmSuccess(profitSharingResult.getOrderId()); + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + + com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest request = new com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest(); + request.setTransactionId(payOrder.getChannelOrderNo()); + request.setUnfreezeUnsplit(true); // 分账完成 解冻金额 + + request.setAppid(WxpayKit.getWxPayConfig(wxServiceWrapper).getAppId()); + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + request.setSubMchId(isvsubMchParams.getSubMchId()); + } + + if(recordList.isEmpty()){ + request.setOutOrderNo(SeqKit.genDivisionBatchId()); // 随机生成一个订单号 + }else{ + request.setOutOrderNo(recordList.get(0).getBatchOrderId()); //取到批次号 + } + + List receivers = new ArrayList<>(); + for (int i = 0; i < recordList.size(); i++) { + + PayOrderDivisionRecord record = recordList.get(i); + if(record.getCalDivisionAmount() <= 0){ + continue; + } + + ProfitSharingReceiver receiver = new ProfitSharingReceiver(); + // 0-个人, 1-商户 (目前仅支持服务商appI获取个人openId, 即: PERSONAL_OPENID, 不支持 PERSONAL_SUB_OPENID ) + receiver.setType(record.getAccType() == 0 ? "PERSONAL_OPENID" : "MERCHANT_ID"); + receiver.setAccount(record.getAccNo()); + receiver.setAmount(record.getCalDivisionAmount()); + receiver.setDescription(record.getPayOrderId() + "分账"); + receivers.add(receiver); + } + //不存在接收账号时,订单完结(解除冻结金额) + if(receivers.isEmpty()){ + return ChannelRetMsg.confirmSuccess(this.divisionFinish(payOrder, mchAppConfigContext)); + } + request.setReceivers(receivers); + + com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult profitSharingResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharing(request); + return ChannelRetMsg.confirmSuccess(profitSharingResult.getOrderId()); + } else { + return ChannelRetMsg.sysError("请选择微信V2或V3模式"); + } + + } catch (WxPayException wxPayException) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException); + return channelRetMsg; + + } catch (Exception e) { + log.error("微信分账失败", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + try{ + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + ProfitSharingReturnRequest request = new ProfitSharingReturnRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, request); + request.setOutOrderNo(payOrderDivisionRecord.getBatchOrderId()); // 原发起分账请求时使用的商户后台系统的分账单号。 + request.setOutReturnNo(payOrderDivisionRefundRecord.getDivisionRefundId()); //商户回退单号 + request.setReturnAccountType("MERCHANT_ID"); // 暂时只支持商户接收方回退 + request.setReturnAccount(payOrderDivisionRecord.getAccNo()); + request.setReturnAmount(payOrderDivisionRefundRecord.getDivisionRefundAmount().intValue()); //金额 + request.setDescription(payOrderDivisionRefundRecord.getPayOrderId() + "退款"); + + ProfitSharingReturnResult profitSharingReturnResult = + wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharingReturn(request); + + // 明确成功 + return ChannelRetMsg.confirmSuccess(profitSharingReturnResult.getReturnNo()); + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + + com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnRequest request = new com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnRequest(); + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + request.setSubMchId(isvsubMchParams.getSubMchId()); + } + + request.setOutOrderNo(payOrderDivisionRecord.getBatchOrderId()); + request.setOutReturnNo(payOrderDivisionRefundRecord.getDivisionRefundId()); + request.setReturnMchid(payOrderDivisionRecord.getAccNo()); + request.setAmount(payOrderDivisionRefundRecord.getDivisionRefundAmount()); + request.setDescription(payOrderDivisionRefundRecord.getPayOrderId() + "退款"); + com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnResult profitSharingReturnResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingReturn(request); + + // 明确成功 + return ChannelRetMsg.confirmSuccess(profitSharingReturnResult.getReturnId()); + + } else { + return ChannelRetMsg.sysError("请选择微信V2或V3模式"); + } + + } catch (WxPayException wxPayException) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + WxpayKit.commonSetErrInfo(channelRetMsg, wxPayException); + return channelRetMsg; + + } catch (Exception e) { + + log.error("请求微信分账回退接口异常!", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg("系统异常:" + e.getMessage()); + return channelRetMsg; + } + + } + + + /** 调用订单的完结接口 (分账对象不存在时) */ + private String divisionFinish(PayOrder payOrder,MchAppConfigContext mchAppConfigContext) throws WxPayException { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + ProfitSharingFinishRequest request = new ProfitSharingFinishRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, request); + + request.setSubAppId(null); // 传入subAppId 将导致签名失败 + + request.setTransactionId(payOrder.getChannelOrderNo()); + request.setOutOrderNo(SeqKit.genDivisionBatchId()); + request.setDescription("完结分账"); + + return wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharingFinish(request).getOrderId(); + }else { + + ProfitSharingUnfreezeRequest request = new ProfitSharingUnfreezeRequest(); + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + request.setSubMchId(isvsubMchParams.getSubMchId()); + } + + request.setTransactionId(payOrder.getChannelOrderNo()); + request.setOutOrderNo(SeqKit.genDivisionBatchId()); + request.setDescription("完结分账"); + ProfitSharingUnfreezeResult profitSharingUnfreezeResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingUnfreeze(request); + + // 明确成功 + return profitSharingUnfreezeResult.getOrderId(); + } + } + + /** 调用订单的完结接口 (分账已完成) */ + @Override + public String divisionFinishAfterDivision(PayOrderDivisionRecord divisionRecord, MchAppConfigContext mchAppConfigContext) { + + try { + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + return null; + }else { + + ProfitSharingUnfreezeRequest request = new ProfitSharingUnfreezeRequest(); + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + request.setSubMchId(isvsubMchParams.getSubMchId()); + } + + request.setTransactionId(divisionRecord.getPayOrderChannelOrderNo()); + request.setOutOrderNo(divisionRecord.getBatchOrderId()); + + request.setDescription("完结分账"); + ProfitSharingUnfreezeResult profitSharingUnfreezeResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().profitSharingUnfreeze(request); + + // 明确成功 + return profitSharingUnfreezeResult.getOrderId(); + } + }catch (WxPayException e) { + log.error("分账完成,调用完结分账失败:", e); + return null; + } + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + throw new BizException("接口不支持"); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayMchApplymentService.java new file mode 100644 index 0000000..513f5b8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayMchApplymentService.java @@ -0,0 +1,385 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.github.binarywang.wxpay.bean.applyment.ApplymentStateQueryResult; +import com.github.binarywang.wxpay.bean.applyment.WxPayApplyment4SubCreateRequest; +import com.github.binarywang.wxpay.bean.applyment.WxPayApplymentCreateResult; +import com.github.binarywang.wxpay.bean.applyment.enums.BankAccountTypeEnum; +import com.github.binarywang.wxpay.bean.applyment.enums.IdTypeEnum; +import com.github.binarywang.wxpay.bean.applyment.enums.SalesScenesTypeEnum; +import com.github.binarywang.wxpay.bean.applyment.enums.SubjectTypeEnum; +import com.github.binarywang.wxpay.bean.media.ImageUploadResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.Applyment4SubService; +import com.github.binarywang.wxpay.service.MerchantMediaService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.Applyment4SubServiceImpl; +import com.github.binarywang.wxpay.service.impl.MerchantMediaServiceImpl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.IdcardInfo; +import com.jeequan.jeepay.core.model.applyment.WxpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.*; + +/*** +* 微信接口进件 +* +* @author zx +* +* @date 2022/1/4 14:54 +*/ +@Service +@Slf4j +public class WxpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired protected SysConfigService sysConfigService; + + @Autowired private ConfigContextQueryService configContextQueryService; + + + @Override + public MchApplyment firstApplyment(MchApplyment mchApplyment) { + + // 获取到 服务商配置信息 + WxpayIsvParams wxpayIsvParams = (WxpayIsvParams)configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), CS.IF_CODE.WXPAY); + + // 特约商户进件相关服务 + Applyment4SubService applyment4SubService = getApplyment4SubService(wxpayIsvParams); + + // 获取详细参数 + WxpayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), WxpayApplymentInfo.class); + + MchApplyment result = new MchApplyment(); + result.setApplyDetailInfo(JSON.toJSONString(info)); //重新更新全量参数(包含imgCache) + + try { + // 超级管理员信息 + WxPayApplyment4SubCreateRequest.ContactInfo contactInfo = WxPayApplyment4SubCreateRequest.ContactInfo.builder() + .contactType(info.getContactType()) // 超级管理员类型 LEGAL:经营者/法人 SUPER:经办人 + .contactName(info.getIdcardName()) // 超级管理员姓名 + .contactEmail(info.getContactEmail()) // 联系邮箱 + .mobilePhone(info.getContactPhone()) // 联系手机 + .build(); + + // 超管为 经办人 + if ("SUPER".equals(info.getContactType())) { + contactInfo.setContactIdDocType("IDENTIFICATION_TYPE_IDCARD"); // 默认身份证 + contactInfo.setContactIdDocCopy(this.uploadImg(info.getContactIdDocCopy(), wxpayIsvParams, info)); // 超管身份证人像照 + contactInfo.setContactIdDocCopyBack(this.uploadImg(info.getContactIdDocCopyBack(), wxpayIsvParams, info)); // 超管身份证国徽照 + contactInfo.setContactName(info.getContactName()); // 超级管理员姓名 + contactInfo.setContactIdNumber(info.getContactIdNumber()); // 超级管理员身份证件号码 + contactInfo.setContactPeriodBegin(info.getContactIdDocPeriodBegin()); // 超管身份证起始有效期 + contactInfo.setContactPeriodEnd(info.getContactIdDocPeriodEnd()); // 超管身份证结束有效期 + contactInfo.setBusinessAuthorizationLetter(this.uploadImg(info.getBusinessAuthorizationLetter(), wxpayIsvParams, info)); // 业务办理授权函 + } + + // 主体资料 + // 法人身份证信息 + WxPayApplyment4SubCreateRequest.SubjectInfo.IdentityInfo.IdCardInfo idCardInfo = WxPayApplyment4SubCreateRequest.SubjectInfo.IdentityInfo.IdCardInfo.builder() + .idCardCopy(this.uploadImg(info.getIdcard1Img(), wxpayIsvParams, info)) // 法人身份证人像面照片 + .idCardNational(this.uploadImg(info.getIdcard2Img(), wxpayIsvParams, info)) // 法人身份证国徽面照片 + .idCardName(info.getIdcardName()) // 法人身份证姓名 + .idCardNumber(info.getIdcardNo()) // 法人身份证号 + .cardPeriodBegin(info.getIdcardEffectBegin()) // 法人身份证起始有效期,格式为yyyy-MM-dd + .cardPeriodEnd(info.getIdcardEffectEnd()) // 法人身份证结束有效期,格式为yyyy-MM-dd,有效期为长期,请填写:长期。 + .build(); + // 主体为企业时 + if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == info.getMerchantType()) { + idCardInfo.setIdCardAddress(info.getIdcardAddress()); // 身份证居住地址 + } + + // 经营者/法人证件信息 + WxPayApplyment4SubCreateRequest.SubjectInfo.IdentityInfo identityInfo = WxPayApplyment4SubCreateRequest.SubjectInfo.IdentityInfo.builder() // 法人信息 + .idDocType(IdTypeEnum.IDENTIFICATION_TYPE_IDCARD) // 证件类型:身份证 + .idCardInfo(idCardInfo) // 经营者/法人信息 + .build(); + // 主体为企业时 + if (info.getMerchantType() == MchApplyment.MERCHANT_TYPE_ENTERPRISE) { + identityInfo.setOwner(info.getOwner()); // 经营者/法人是最终受益人 + } + + WxPayApplyment4SubCreateRequest.SubjectInfo subjectInfo = WxPayApplyment4SubCreateRequest.SubjectInfo.builder() + .subjectType(convertMerchantType(info.getMerchantType())) // 主体类型 + .businessLicenseInfo(WxPayApplyment4SubCreateRequest.SubjectInfo.BusinessLicenseInfo.builder() + .licenseNumber(info.getLicenseNo()) // 营业执照号 + .licenseCopy(this.uploadImg(info.getLicenseImg(), wxpayIsvParams, info)) // 营业执照图片 + .licenseAddress(info.getLicenseAddress()) // 注册地址 + .periodBegin(info.getLicenseEffectBegin()) + .periodEnd(info.getLicenseEffectEnd()) + .merchantName(info.getMchFullName()) // 营业执照商户名称 + .legalPerson(info.getIdcardName()) // 个体户经营者/法人姓名 + .build()) + .identityInfo(identityInfo) + .build(); + + + // 受益人信息(JSON数组字符串),企业必传 + if(info.getMerchantType() == MchApplyment.MERCHANT_TYPE_ENTERPRISE && info.getCompanyBeneficiaryList() != null){ + List uboInfoList = new LinkedList<>(); + + for (IdcardInfo idcardInfo : info.getCompanyBeneficiaryList()) { + WxPayApplyment4SubCreateRequest.SubjectInfo.UboInfo uboInfo = new WxPayApplyment4SubCreateRequest.SubjectInfo.UboInfo(); + + uboInfo.setUboIdDocType(IdTypeEnum.IDENTIFICATION_TYPE_IDCARD); + uboInfo.setUboIdDocCopy(this.uploadImg(idcardInfo.getIdcard1Img(), wxpayIsvParams, info)); + uboInfo.setUboIdDocCopyBack(this.uploadImg(idcardInfo.getIdcard2Img(), wxpayIsvParams, info)); + uboInfo.setUboIdDocName(idcardInfo.getIdcardName()); + uboInfo.setUboIdDocNumber(idcardInfo.getIdcardNo()); + uboInfo.setUboIdDocAddress(idcardInfo.getIdcardAddress()); + uboInfo.setUboPeriodBegin(idcardInfo.getIdcardEffectBegin()); + uboInfo.setUboPeriodEnd(idcardInfo.getIdcardEffectEnd()); + + uboInfoList.add(uboInfo); + } + + subjectInfo.setUboInfoList(uboInfoList); + } + + // 经营资料 + WxPayApplyment4SubCreateRequest.BusinessInfo businessInfo = WxPayApplyment4SubCreateRequest.BusinessInfo.builder() + .merchantShortname(info.getMchShortName()) // 商户简称 + .servicePhone(info.getServicePhone()) // 客服电话 + .salesInfo(WxPayApplyment4SubCreateRequest.BusinessInfo.SalesInfo.builder() + .salesScenesType(Collections.singletonList(SalesScenesTypeEnum.SALES_SCENES_STORE)) // 经营场景类型 SALES_SCENES_STORE:线下门店 + .bizStoreInfo(WxPayApplyment4SubCreateRequest.BusinessInfo.SalesInfo.BizStoreInfo.builder() + .bizStoreName(info.getStoreName()) // 经营店铺名称,签约收单产品必填 + .bizAddressCode(info.getAreaCode().getString(2)) // 门店省市编码 + .bizStoreAddress(info.getAddress()) // 门店详细地址 + .storeEntrancePic(Collections.singletonList(this.uploadImg(info.getStoreOuterImg(), wxpayIsvParams, info))) // 门店门头照片 + .indoorPic(Collections.singletonList(this.uploadImg(info.getStoreInnerImg(), wxpayIsvParams, info))) // 店内环境照片 + .build()) + .build()) + .build(); + + // 结算规则 + WxPayApplyment4SubCreateRequest.SettlementInfo settlementInfo = WxPayApplyment4SubCreateRequest.SettlementInfo.builder() + .settlementId(info.getSettlementId()) // 入驻结算规则ID,参考:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/terms_definition/chapter1_1_3.shtml#part-7 + .qualificationType(info.getMccCode()) + .activitiesId(info.getActivitiesId()) + .activitiesRate(info.convertPaywayFeeList2String()) + .build(); + if (StringUtils.isNotBlank(info.getQualifications())) { + settlementInfo.setQualifications(Arrays.asList(this.uploadImg(info.getQualifications(), wxpayIsvParams, info))); + } + + + // 结算银行账户 + String bankAddressCode = null; + if(info.getSettAccountBankBranchAreaCode() != null && info.getSettAccountBankBranchAreaCode().size() > 1){ + bankAddressCode = info.getSettAccountBankBranchAreaCode().getString(2); + } + WxPayApplyment4SubCreateRequest.BankAccountInfo bankAccountInfo = WxPayApplyment4SubCreateRequest.BankAccountInfo.builder() + .bankAccountType(convertSettAccountType(info.getSettAccountType())) // 账户类型 + .accountName(info.getSettAccountName()) // 开户名称 + .accountNumber(info.getSettAccountNo()) // 银行账号 + .accountBank(info.getSettAccountBankName()) // 开户银行 + .bankAddressCode(bankAddressCode) // 开户银行省市编码 + .build(); + + if ("其他银行".equals(info.getSettAccountBankName())) { + bankAccountInfo.setBankName(info.getSettAccountBankBranchName()); // 开户银行支行名称 + } + + // 进件请求 + WxPayApplyment4SubCreateRequest request = WxPayApplyment4SubCreateRequest.builder() + .businessCode(mchApplyment.getApplyId()) + .contactInfo(contactInfo) + .subjectInfo(subjectInfo) + .businessInfo(businessInfo) + .settlementInfo(settlementInfo) + .bankAccountInfo(bankAccountInfo) + .build(); + + + log.info("请求微信进件接口"); + WxPayApplymentCreateResult createResult = applyment4SubService.createApply(request); + + if (createResult != null) { + result.setState(MchApplyment.STATE_AUDITING); + result.setChannelApplyNo(createResult.getApplymentId()); // 放置请求ID + } else { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + return result; + } catch (WxPayException e) { + log.error("微信进件失败", e); + + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(e.getErrCode() + "[" + e.getCustomErrorMsg() + "]"); + return result; + } catch (IOException e) { + log.error("微信进件失败", e); + + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + return result; + } + } + + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayIsvParams wxpayIsvParams = (WxpayIsvParams)configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), CS.IF_CODE.WXPAY); + + // 特约商户进件相关服务 + Applyment4SubService applyment4SubService = getApplyment4SubService(wxpayIsvParams); + + // 返回 + MchApplyment result = new MchApplyment(); + + try { + ApplymentStateQueryResult queryResult = applyment4SubService.queryApplyStatusByBusinessCode(mchApplyment.getApplyId()); + + // 放置请求ID + result.setChannelApplyNo(queryResult.getApplymentId()); + result.setState(mchApplyment.getState()); + + switch (queryResult.getApplymentState()) { + case APPLYMENT_STATE_EDITTING: // 编辑中,提交申请发生错误导致,请尝试重新提交。 + case APPLYMENT_STATE_REJECTED: // 已驳回,请按照驳回原因修改申请资料。 + case APPLYMENT_STATE_CANCELED: // 已作废,申请单已被撤销。 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(queryResult.getApplymentStateMsg() + "【" + queryResult.getAuditDetail() + "】"); + break; + case APPLYMENT_STATE_AUDITING: // 审核中 + result.setState(MchApplyment.STATE_AUDITING); + break; + case APPLYMENT_STATE_TO_BE_CONFIRMED: // 待账户验证,请超级管理员使用微信打开返回的“签约链接”,根据页面指引完成账户验证。 + result.setState(MchApplyment.STATE_WAIT_VERIFY); + result.setApplyErrorInfo(queryResult.getSignUrl()); + break; + case APPLYMENT_STATE_TO_BE_SIGNED: // 待签约,请超级管理员使用微信打开返回的“签约链接”,根据页面指引完成签约。 + result.setState(MchApplyment.STATE_WAIT_SIGN); + result.setApplyErrorInfo(queryResult.getSignUrl()); + break; + case APPLYMENT_STATE_SIGNING: // 开通权限中,系统开通相关权限中,请耐心等待。 + result.setState(mchApplyment.getState()); + break; + case APPLYMENT_STATE_FINISHED: // 已完成,商户入驻申请已完成。 + result.setState(MchApplyment.STATE_SUCCESS); + // 封装支付参数 + WxpayIsvsubMchParams params = new WxpayIsvsubMchParams(); + params.setSubMchId(queryResult.getSubMchid()); + result.setSuccResParameter(JSON.toJSONString(params)); + } + } catch (WxPayException e) { + log.error("微信进件失败", e); + + result.setApplyErrorInfo(e.getErrCode() + "[" + e.getCustomErrorMsg() + "]"); + } + + return result; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + + /** 上传照片, 返回mediaId **/ + private String uploadImg(String img, WxpayIsvParams wxpayIsvParams, WxpayApplymentInfo info) throws IOException, WxPayException { + + if(StringUtils.isEmpty(img)){ + return null; + } + + if(info.getUploadImgCache() != null && StringUtils.isNotEmpty(info.getUploadImgCache().get(img))){ + return info.getUploadImgCache().get(img); + } + + // 微信上传服务 + MerchantMediaService mediaService = getMerchantMediaService(wxpayIsvParams); + + // 请求地址 + ImageUploadResult uploadResult = mediaService.imageUploadV3(new ByteArrayInputStream(HttpUtil.downloadBytes(img)), img); + log.info("微信上传图片响应数据:{}", uploadResult.toString()); + + String mediaId = uploadResult.getMediaId(); + + if(info.getUploadImgCache() == null){ + info.setUploadImgCache(new HashMap<>()); + } + info.getUploadImgCache().put(img, mediaId); + return mediaId; + } + + /**获取 wxJava 特约商户进件service */ + private Applyment4SubService getApplyment4SubService(WxpayIsvParams wxpayIsvParams) { + return new Applyment4SubServiceImpl(getWxPayService(wxpayIsvParams)); + } + + /** 获取 wxJava 媒体文件上传service */ + private MerchantMediaService getMerchantMediaService(WxpayIsvParams wxpayIsvParams) { + return new MerchantMediaServiceImpl(getWxPayService(wxpayIsvParams)); + } + + /** 获取 wxJava WxPayService */ + private WxPayService getWxPayService(WxpayIsvParams wxpayIsvParams) { + return WxServiceWrapper.buildWxServiceWrapper(wxpayIsvParams, null).getWxPayService(); + } + + /** 主体类型转换:标准格式 ---》 接口自定义格式 **/ + public SubjectTypeEnum convertMerchantType(Byte merchantType){ + + if(merchantType == null){ + return null; + } + + if(merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return SubjectTypeEnum.SUBJECT_TYPE_INDIVIDUAL; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return SubjectTypeEnum.SUBJECT_TYPE_ENTERPRISE; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_GOV){ + return SubjectTypeEnum.SUBJECT_TYPE_INSTITUTIONS; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_OTHER){ + return SubjectTypeEnum.SUBJECT_TYPE_OTHERS; + } + return null; + } + + /** 结算账号类型转换:标准格式 ---》 接口自定义格式 **/ + public BankAccountTypeEnum convertSettAccountType(String settAccountType){ + + if(StringUtils.isEmpty(settAccountType)){ + return null; + } + + if(settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE)){ + return BankAccountTypeEnum.BANK_ACCOUNT_TYPE_CORPORATE; + }else if(settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL)){ + return BankAccountTypeEnum.BANK_ACCOUNT_TYPE_PERSONAL; + } + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderCloseService.java new file mode 100644 index 0000000..85dd09c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderCloseService.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest; +import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 微信关闭订单 + * + * @author xiaoyu + * + * @date 2022/1/24 17:25 + */ +@Service +public class WxpayPayOrderCloseService implements IPayOrderCloseService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + try { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + WxPayOrderCloseRequest req = new WxPayOrderCloseRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, req); + + req.setOutTradeNo(payOrder.getPayOrderId()); + + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + WxPayOrderCloseResult result = wxPayService.closeOrder(req); + + if("SUCCESS".equals(result.getResultCode())){ //关闭订单成功 + return ChannelRetMsg.confirmSuccess(null); + }else if("FAIL".equals(result.getResultCode())){ //关闭订单失败 + return ChannelRetMsg.confirmFail(); //关闭失败 + }else{ + return ChannelRetMsg.waiting(); //关闭中 + } + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { //V3 + + String reqUrl; + JSONObject reqJson = new JSONObject(); + if(mchAppConfigContext.isIsvsubMch()){ // 特约商户 + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrder.getIfCode()); + reqUrl = String.format("/v3/pay/partner/transactions/out-trade-no/%s/close", payOrder.getPayOrderId()); + reqJson.put("sp_mchid", wxServiceWrapper.getWxPayService().getConfig().getMchId()); + reqJson.put("sub_mchid", isvsubMchParams.getSubMchId()); + }else { + reqUrl = String.format("/v3/pay/transactions/out-trade-no/%s/close", payOrder.getPayOrderId()); + reqJson.put("mchid", wxServiceWrapper.getWxPayService().getConfig().getMchId()); + } + + WxpayV3Util.closeOrderV3(reqUrl, reqJson, wxServiceWrapper.getWxPayService()); + return ChannelRetMsg.confirmSuccess(null); + } + return ChannelRetMsg.confirmFail(); + } catch (WxPayException e) { + return ChannelRetMsg.sysError(e.getReturnMsg()); + } catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderQueryService.java new file mode 100644 index 0000000..afd674e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPayOrderQueryService.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; +import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 微信查单接口 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Service +public class WxpayPayOrderQueryService implements IPayOrderQueryService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + try { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + WxPayOrderQueryRequest req = new WxPayOrderQueryRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, req); + + req.setOutTradeNo(payOrder.getPayOrderId()); + + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + WxPayOrderQueryResult result = wxPayService.queryOrder(req); + + if("SUCCESS".equals(result.getTradeState())){ //支付成功 + return ChannelRetMsg.confirmSuccess(result.getTransactionId(), result.getTransactionId(), payOrder.getPayOrderId(),null); + }else if("USERPAYING".equals(result.getTradeState())){ //支付中,等待用户输入密码 + return ChannelRetMsg.waiting(); //支付中 + }else if("CLOSED".equals(result.getTradeState()) + || "REVOKED".equals(result.getTradeState()) + || "PAYERROR".equals(result.getTradeState())){ //CLOSED—已关闭, REVOKED—已撤销(刷卡支付), PAYERROR--支付失败(其他原因,如银行返回失败) + return ChannelRetMsg.confirmFail(); //支付失败 + }else{ + return ChannelRetMsg.waiting(); + } + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { //V3 + + String reqUrl; + String query; + if(mchAppConfigContext.isIsvsubMch()){ // 特约商户 + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrder.getIfCode()); + reqUrl = String.format("/v3/pay/partner/transactions/out-trade-no/%s", payOrder.getPayOrderId()); + query = String.format("?sp_mchid=%s&sub_mchid=%s", wxServiceWrapper.getWxPayService().getConfig().getMchId(), isvsubMchParams.getSubMchId()); + }else { + reqUrl = String.format("/v3/pay/transactions/out-trade-no/%s", payOrder.getPayOrderId()); + query = String.format("?mchid=%s", wxServiceWrapper.getWxPayService().getConfig().getMchId()); + } + JSONObject resultJSON = WxpayV3Util.queryOrderV3(reqUrl + query, wxServiceWrapper.getWxPayService()); + + String channelState = resultJSON.getString("trade_state"); + if ("SUCCESS".equals(channelState)) { + return ChannelRetMsg.confirmSuccess(resultJSON.getString("transaction_id"), resultJSON.getString("transaction_id"), payOrder.getPayOrderId(),null); + }else if("USERPAYING".equals(channelState)){ //支付中,等待用户输入密码 + return ChannelRetMsg.waiting(); //支付中 + }else if("CLOSED".equals(channelState) + || "REVOKED".equals(channelState) + || "PAYERROR".equals(channelState)){ //CLOSED—已关闭, REVOKED—已撤销(刷卡支付), PAYERROR--支付失败(其他原因,如银行返回失败) + return ChannelRetMsg.confirmFail(); //支付失败 + }else{ + return ChannelRetMsg.waiting(); + } + + }else { + return ChannelRetMsg.waiting(); + } + + } catch (WxPayException e) { + return ChannelRetMsg.sysError(e.getReturnMsg()); + } catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPaymentService.java new file mode 100644 index 0000000..6c73f13 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayPaymentService.java @@ -0,0 +1,221 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 支付接口: 微信官方 +* 支付方式: 自适应 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Service +public class WxpayPaymentService extends AbstractPaymentService { + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + // 微信API版本 + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + String apiVersion = wxServiceWrapper.getApiVersion(); + if (CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } else if (CS.PAY_IF_VERSION.WX_V3.equals(apiVersion)) { + return PaywayUtil.getRealPaywayV3Service(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } else { + throw new BizException("不支持的微信支付API版本"); + } + + } + + /** + * 构建微信统一下单请求数据 + * @param payOrder + * @return + */ + public WxPayUnifiedOrderRequest buildUnifiedOrderRequest(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + String payOrderId = payOrder.getPayOrderId(); + + // 微信统一下单请求对象 + WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); + request.setOutTradeNo(payOrderId); + request.setBody(payOrder.getSubject()); + request.setDetail(payOrder.getBody()); + request.setFeeType("CNY"); + request.setTotalFee(payOrder.getFindAmt().intValue()); + request.setSpbillCreateIp(payOrder.getClientIp()); + request.setNotifyUrl(getNotifyUrl()); + request.setProductId(DateKit.currentTimeMillis()+""); + request.setTimeExpire(DateUtil.format(payOrder.getExpiredTime(), DatePattern.PURE_DATETIME_PATTERN)); + + // 订单分账, 将冻结商户资金。 + if(isDivisionOrder(payOrder)){ + request.setProfitSharing("Y"); + } + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + request.setSubMchId(isvsubMchParams.getSubMchId()); + + // 当配置了subMchId时, 需要显式设置该参数, 此时支付成功后可以获取到subOpenId参数。 + // 注意: 当小程序支付时会有不同的判断。 可能会对subAppId重新赋值。 + if (StringUtils.isNotBlank(isvsubMchParams.getSubMchAppId())) { + request.setSubAppId(isvsubMchParams.getSubMchAppId()); + } + } + + return request; + } + + + /** + * 构建微信APIV3接口 统一下单请求数据 20220425新改版 + * @author terrfly + * @param payOrder + * @return + */ + public WxpayV3OrderRequestModel buildV3OrderRequestModel(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + + String payOrderId = payOrder.getPayOrderId(); + + // 微信统一下单请求对象 + WxpayV3OrderRequestModel result = new WxpayV3OrderRequestModel(); + result.setOutTradeNo(payOrderId); + result.setDescription(payOrder.getSubject()); + + // 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,示例值:2018-06-08T10:34:56+08:00 + result.setTimeExpire(String.format("%sT%s+08:00", DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATE_FORMAT), DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_TIME_FORMAT))); + + result.setNotifyUrl(getNotifyUrl(payOrderId)); + + // 订单金额 + result.setAmount(new WxpayV3OrderRequestModel.Amount().setCurrency("CNY").setTotal(payOrder.getFindAmt().intValue())); + + // 场景信息 + result.setSceneInfo(new WxpayV3OrderRequestModel.SceneInfo().setPayerClientIp(payOrder.getClientIp())); + + //订单分账, 将冻结商户资金。 + if(isDivisionOrder(payOrder)){ + result.setSettleInfo(new WxpayV3OrderRequestModel.SettleInfo().setProfitSharing(true)); + } + + WxPayService wxPayService = configContextQueryService.getWxServiceWrapper(mchAppConfigContext).getWxPayService(); + + if(mchAppConfigContext.isIsvsubMch()){ // 特约商户 + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + + // 服务商相关参数 + result.setSpAppid(wxPayService.getConfig().getAppId()); + result.setSpMchid(wxPayService.getConfig().getMchId()); + result.setSubMchid(isvsubMchParams.getSubMchId()); + + }else { // 普通商户 + + result.setNormalMchid(wxPayService.getConfig().getMchId()); + result.setNormalAppid(wxPayService.getConfig().getAppId()); + + } + + return result; + } + + + /** + * 构建微信APIV3接口 统一下单请求数据 + * @param payOrder + * @return + */ + public JSONObject buildV3OrderRequest(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + String payOrderId = payOrder.getPayOrderId(); + + // 微信统一下单请求对象 + JSONObject reqJSON = new JSONObject(); + reqJSON.put("out_trade_no", payOrderId); + reqJSON.put("description", payOrder.getSubject()); + // 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,示例值:2018-06-08T10:34:56+08:00 + reqJSON.put("time_expire", String.format("%sT%s+08:00", DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATE_FORMAT), DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_TIME_FORMAT))); + reqJSON.put("notify_url", getNotifyUrl(payOrderId)); + + JSONObject amount = new JSONObject(); + amount.put("total", payOrder.getAmount().intValue()); + amount.put("currency", "CNY"); + reqJSON.put("amount", amount); + + JSONObject sceneInfo = new JSONObject(); + sceneInfo.put("payer_client_ip", payOrder.getClientIp()); + reqJSON.put("scene_info", sceneInfo); + + //订单分账, 将冻结商户资金。 + if(isDivisionOrder(payOrder)){ + JSONObject settleInfo = new JSONObject(); + settleInfo.put("profit_sharing", true); + reqJSON.put("settle_info", settleInfo); + } + + WxPayService wxPayService = configContextQueryService.getWxServiceWrapper(mchAppConfigContext).getWxPayService(); + if(mchAppConfigContext.isIsvsubMch()){ // 特约商户 + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + reqJSON.put("sp_appid", wxPayService.getConfig().getAppId()); + reqJSON.put("sp_mchid", wxPayService.getConfig().getMchId()); + reqJSON.put("sub_mchid", isvsubMchParams.getSubMchId()); + + + // 有可能被其他支付方式替换 + if (StringUtils.isNotBlank(isvsubMchParams.getSubMchAppId())) { + reqJSON.put("sub_appid", isvsubMchParams.getSubMchAppId()); + } + }else { // 普通商户 + + reqJSON.put("mchid", wxPayService.getConfig().getMchId()); + + // 有可能被其他支付方式替换 + reqJSON.put("appid", wxPayService.getConfig().getAppId()); + + + } + + return reqJSON; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayRefundService.java new file mode 100644 index 0000000..f14d122 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayRefundService.java @@ -0,0 +1,193 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest; +import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; +import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult; +import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +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.params.wxpay.WxpayIsvsubMchParams; +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; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* + * 退款接口: 微信官方 + * + * @author xiaoyu + * + * @date 2021/6/17 16:38 + */ +@Slf4j +@Service +public class WxpayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + /** 微信退款接口 **/ + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + try { + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + WxPayRefundRequest req = new WxPayRefundRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, req); + + req.setOutTradeNo(payOrder.getPayOrderId()); // 商户订单号 + req.setOutRefundNo(refundOrder.getRefundOrderId()); // 退款单号 + req.setTotalFee(payOrder.getAmount().intValue()); // 订单总金额 + req.setRefundFee(refundOrder.getRefundAmount().intValue()); // 退款金额 + req.setNotifyUrl(getNotifyUrl(refundOrder.getRefundOrderId())); // 回调url + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + WxPayRefundResult result = wxPayService.refundV2(req); + if("SUCCESS".equals(result.getResultCode())){ // 退款发起成功,结果主动查询 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setChannelOrderId(result.getRefundId()); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(result.getErrCode()); + channelRetMsg.setChannelErrMsg(WxpayKit.appendErrMsg(result.getReturnMsg(), result.getErrCodeDes())); + } + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { //V3 + // 微信统一下单请求对象 + JSONObject reqJSON = new JSONObject(); + reqJSON.put("out_trade_no", refundOrder.getPayOrderId()); // 订单号 + reqJSON.put("out_refund_no", refundOrder.getRefundOrderId()); // 退款订单号 + reqJSON.put("notify_url", getNotifyUrl(refundOrder.getRefundOrderId())); // 回调地址 + + JSONObject amountJson = new JSONObject(); + amountJson.put("refund", refundOrder.getRefundAmount());// 退款金额 + amountJson.put("total", payOrder.getAmount());// 订单总金额 + amountJson.put("currency", "CNY");// 币种 + reqJSON.put("amount", amountJson); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + if(mchAppConfigContext.isIsvsubMch()){ // 特约商户 + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + reqJSON.put("sub_mchid", isvsubMchParams.getSubMchId()); + } + + JSONObject resultJSON = WxpayV3Util.refundV3(reqJSON, wxServiceWrapper.getWxPayService()); + String status = resultJSON.getString("status"); + if("SUCCESS".equals(status)){ // 退款成功 + String refundId = resultJSON.getString("refund_id"); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setChannelOrderId(refundId); + }else if ("PROCESSING".equals(status)){ // 退款处理中 + String refundId = resultJSON.getString("refund_id"); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setChannelOrderId(refundId); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg(status); + } + + } + return channelRetMsg; + } catch (WxPayException e) { + log.error("微信退款WxPayException异常: ", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + return channelRetMsg; + + } catch (Exception e) { + log.error("微信退款Exception异常: ", e); + return ChannelRetMsg.sysError(e.getMessage()); + } + } + + /** 微信退款查单接口 **/ + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + try { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + WxPayRefundQueryRequest req = new WxPayRefundQueryRequest(); + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, req); + + req.setOutRefundNo(refundOrder.getRefundOrderId()); // 退款单号 + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + WxPayRefundQueryResult result = wxPayService.refundQueryV2(req); + if("SUCCESS".equals(result.getResultCode())){ // 退款成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setChannelErrMsg(result.getReturnMsg()); + } + + }else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { //V3 + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + JSONObject resultJSON = null; + if (mchAppConfigContext.isIsvsubMch()) { + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + resultJSON = WxpayV3Util.refundQueryV3Isv(refundOrder.getRefundOrderId(), wxPayService, isvsubMchParams.getSubMchId()); + }else { + resultJSON = WxpayV3Util.refundQueryV3(refundOrder.getRefundOrderId(), wxPayService); + } + String status = resultJSON.getString("status"); + if("SUCCESS".equals(status)){ // 退款成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setChannelErrMsg(status); + } + } + return channelRetMsg; + } catch (WxPayException e) { + log.error("微信退款查询WxPayException异常: ", e); + return ChannelRetMsg.sysError(e.getReturnMsg()); + } catch (Exception e) { + log.error("微信退款查询Exception异常: ", e); + return ChannelRetMsg.sysError(e.getMessage()); + } + } + + /** + * 是否支持平台户退款 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayTransferService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayTransferService.java new file mode 100644 index 0000000..d176aba --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/WxpayTransferService.java @@ -0,0 +1,196 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay; + +import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult; +import com.github.binarywang.wxpay.bean.entpay.EntPayRequest; +import com.github.binarywang.wxpay.bean.transfer.TransferBatchDetailResult; +import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import com.jeequan.jeepay.db.entity.TransferSubjectEntity; +import com.jeequan.jeepay.db.entity.TransferWalletEntity; +import com.jeequan.jeepay.thirdparty.channel.AbstractTransferService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** +* 转账接口: 微信官方 +* +* @author terrfly +* +* @date 2021/8/11 14:05 +*/ +@Slf4j +@Service +public class WxpayTransferService extends AbstractTransferService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public boolean isSupport(String entryType) { + + // 微信仅支持 零钱 和 银行卡入账方式 + if(TransferOrder.ENTRY_WX_CASH.equals(entryType) || TransferOrder.ENTRY_BANK_CARD.equals(entryType)){ + return true; + } + + return false; + } + + @Override + public String preCheck(TransferOrderRQ bizRQ, TransferOrder transferOrder) { + super.preCheck(bizRQ, transferOrder); + + /** + * 微信企业付款到零钱 产品:不支持服务商模式,参考如下链接: + * https://developers.weixin.qq.com/community/develop/doc/0004888f8603b042a45c632355a400?highLine=%25E4%25BB%2598%25E6%25AC%25BE%25E5%2588%25B0%25E9%259B%25B6%25E9%2592%25B1%2520%2520%25E6%259C%258D%25E5%258A%25A1%25E5%2595%2586 + * 微信官方解答: 目前企业付款到零钱,是不支持服务商模式的哈,如果特约商户需要使用该功能,请自行登录商户平台申请使用。 + **/ + if(transferOrder.getMchType() == CS.MCH_TYPE_ISVSUB){ + return "微信子商户暂不支持转账业务"; + } + + return null; + } + + @Override + public ChannelRetMsg transfer(TransferOrderRQ bizRQ, TransferOrder transferOrder){ + + try { + TransferSubjectEntity transferSubject = transferSubjectService.getById(transferOrder.getTransferSubjectIdFq()); + WxpayIsvParams wxpayIsvParams = (WxpayIsvParams) configContextQueryService.queryTransferIsvParams(transferSubject); + TransferWalletEntity transferWallet = transferWalletService.getByApplyId(transferOrder.getTransferSubjectIdFq(), null); + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(transferWallet, wxpayIsvParams); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + EntPayRequest request = new EntPayRequest(); + request.setMchAppid(wxServiceWrapper.getWxPayService().getConfig().getAppId()); // 商户账号appid + request.setMchId(wxServiceWrapper.getWxPayService().getConfig().getMchId()); //商户号 + + request.setPartnerTradeNo(transferOrder.getTransferId()); //商户订单号 + request.setOpenid(transferOrder.getAccountNo()); //openid + request.setAmount(transferOrder.getAmount().intValue()); //付款金额,单位为分 + request.setSpbillCreateIp(transferOrder.getClientIp()); + request.setDescription(transferOrder.getTransferDesc()); //付款备注 + if (StringUtils.isNotEmpty(transferOrder.getAccountName())) { + request.setReUserName(transferOrder.getAccountName()); + request.setCheckName("FORCE_CHECK"); + } else { + request.setCheckName("NO_CHECK"); + } + + wxServiceWrapper.getWxPayService().getEntPayService().entPay(request); + return ChannelRetMsg.waiting(); + } else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + TransferBatchesRequest request = new TransferBatchesRequest(); + request.setAppid(wxServiceWrapper.getWxPayService().getConfig().getAppId()); + request.setTotalAmount(transferOrder.getAmount().intValue()); + request.setTotalNum(1); + request.setOutBatchNo(transferOrder.getTransferId()); + request.setBatchName(transferOrder.getAccountName()); + request.setBatchRemark(transferOrder.getTransferDesc()); + + List list = new ArrayList<>(); + TransferBatchesRequest.TransferDetail transferDetail = new TransferBatchesRequest.TransferDetail(); + transferDetail.setOutDetailNo(transferOrder.getTransferId()); + transferDetail.setOpenid(transferOrder.getAccountNo()); + transferDetail.setTransferAmount(transferOrder.getAmount().intValue()); //付款金额,单位为分 + transferDetail.setUserName(transferOrder.getAccountName()); + transferDetail.setTransferRemark(transferOrder.getTransferDesc()); + list.add(transferDetail); + request.setTransferDetailList(list); + + wxServiceWrapper.getWxPayService().getTransferService().transferBatches(request); + return ChannelRetMsg.waiting(); + } else { + return ChannelRetMsg.sysError("请选择微信V2或V3模式"); + } + + } catch (WxPayException e) { + + //出现未明确的错误码时(SYSTEMERROR等),请务必用原商户订单号重试,或通过查询接口确认此次付款的结果。 + if("SYSTEMERROR".equalsIgnoreCase(e.getErrCode())){ + return ChannelRetMsg.waiting(); + } + + return ChannelRetMsg.confirmFail(null, + WxpayKit.appendErrCode(e.getReturnMsg(), e.getErrCode()), + WxpayKit.appendErrMsg(e.getReturnMsg(), StringUtils.defaultIfEmpty(e.getErrCodeDes(), e.getCustomErrorMsg()))); + + } catch (Exception e) { + log.error("转账异常:", e); + return ChannelRetMsg.waiting(); + } + } + + @Override + public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) { + try { + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + + if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2 + + EntPayQueryResult entPayQueryResult = wxServiceWrapper.getWxPayService().getEntPayService().queryEntPay(transferOrder.getTransferId()); + + // SUCCESS,明确成功 + if("SUCCESS".equalsIgnoreCase(entPayQueryResult.getStatus())){ + return ChannelRetMsg.confirmSuccess(entPayQueryResult.getDetailId()); + } else if ("FAILED".equalsIgnoreCase(entPayQueryResult.getStatus())){ // FAILED,明确失败 + return ChannelRetMsg.confirmFail(entPayQueryResult.getStatus(), entPayQueryResult.getReason()); + } else{ + return ChannelRetMsg.waiting(); + } + } else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) { + + TransferBatchDetailResult transferBatchDetailResult = + wxServiceWrapper.getWxPayService().getTransferService().transferBatchesOutBatchNoDetail(transferOrder.getTransferId(), transferOrder.getTransferId()); + + // SUCCESS,明确成功 + if("SUCCESS".equalsIgnoreCase(transferBatchDetailResult.getDetailStatus())){ + return ChannelRetMsg.confirmSuccess(transferBatchDetailResult.getDetailId()); + } else if ("FAIL".equalsIgnoreCase(transferBatchDetailResult.getDetailStatus())){ // FAIL,明确失败 + return ChannelRetMsg.confirmFail(transferBatchDetailResult.getDetailStatus(), transferBatchDetailResult.getFailReason()); + } else{ + return ChannelRetMsg.waiting(); + } + } else { + return ChannelRetMsg.sysError("请选择微信V2或V3模式"); + } + + } catch (WxPayException e) { + + // 如果查询单号对应的数据不存在,那么数据不存在的原因可能是:(1)付款还在处理中;(2)付款处理失败导致付款订单没有落地,务必再次查询确认此次付款的结果。 + if("NOT_FOUND".equalsIgnoreCase(e.getErrCode())){ + return ChannelRetMsg.waiting(); + } + + return ChannelRetMsg.confirmFail(null, + WxpayKit.appendErrCode(e.getReturnMsg(), e.getErrCode()), + WxpayKit.appendErrMsg(e.getReturnMsg(), StringUtils.defaultIfEmpty(e.getErrCodeDes(), e.getCustomErrorMsg()))); + + } catch (Exception e) { + log.error("转账状态查询异常:", e); + return ChannelRetMsg.waiting(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayKit.java new file mode 100644 index 0000000..e6065d1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayKit.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.kits; + +import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.apache.commons.lang3.StringUtils; + +/* +* 【微信支付】支付通道工具包 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +public class WxpayKit { + + /** 放置 isv特殊信息 **/ + public static void putApiIsvInfo(MchAppConfigContext mchAppConfigContext, BaseWxPayRequest req){ + + //不是特约商户, 无需放置此值 + if(!mchAppConfigContext.isIsvsubMch()){ + return ; + } + + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + + WxpayIsvsubMchParams isvsubMchParams = + (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + req.setSubMchId(isvsubMchParams.getSubMchId()); + req.setSubAppId(isvsubMchParams.getSubMchAppId()); + } + + /** 构造服务商 + 商户配置 wxPayConfig **/ + public static WxPayConfig getWxPayConfig(WxServiceWrapper wxServiceWrapper){ + return wxServiceWrapper.getWxPayService().getConfig(); + } + + public static String appendErrCode(String code, String subCode){ + return StringUtils.defaultIfEmpty(subCode, code); //优先: subCode + } + + public static String appendErrMsg(String msg, String subMsg){ + + if(StringUtils.isNotEmpty(msg) && StringUtils.isNotEmpty(subMsg) ){ + return msg + "【" + subMsg + "】"; + } + return StringUtils.defaultIfEmpty(subMsg, msg); + } + + public static void commonSetErrInfo(ChannelRetMsg channelRetMsg, WxPayException wxPayException){ + + channelRetMsg.setChannelErrCode(appendErrCode( wxPayException.getReturnCode(), wxPayException.getErrCode() )); + channelRetMsg.setChannelErrMsg(appendErrMsg( "OK".equalsIgnoreCase(wxPayException.getReturnMsg()) ? null : wxPayException.getReturnMsg(), wxPayException.getErrCodeDes() )); + + // 如果仍然为空 + if(StringUtils.isEmpty(channelRetMsg.getChannelErrMsg())){ + channelRetMsg.setChannelErrMsg(StringUtils.defaultIfEmpty(wxPayException.getCustomErrorMsg(), wxPayException.getMessage())); + } + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayV3Util.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayV3Util.java new file mode 100644 index 0000000..8ec4091 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/kits/WxpayV3Util.java @@ -0,0 +1,106 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.kits; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 15:22 2021/5/26 +*/ +@Slf4j +public class WxpayV3Util { + + private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com"; + public static final Map NORMALMCH_URL_MAP = new HashMap<>(); + static { + NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.APP, "/v3/pay/transactions/app"); + NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.JSAPI, "/v3/pay/transactions/jsapi"); + NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.NATIVE, "/v3/pay/transactions/native"); + NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.MWEB, "/v3/pay/transactions/h5"); + } + + public static final Map ISV_URL_MAP = new HashMap<>(); + static { + ISV_URL_MAP.put(WxPayConstants.TradeType.APP, "/v3/pay/partner/transactions/app"); + ISV_URL_MAP.put(WxPayConstants.TradeType.JSAPI, "/v3/pay/partner/transactions/jsapi"); + ISV_URL_MAP.put(WxPayConstants.TradeType.NATIVE, "/v3/pay/partner/transactions/native"); + ISV_URL_MAP.put(WxPayConstants.TradeType.MWEB, "/v3/pay/partner/transactions/h5"); + } + + public interface WxCallBack{ + /** 生成返回数据 */ + String genPayInfo(JSONObject wxRes); + } + + /** + * 功能描述: + * 统一调起微信支付请求 + * @param model + * @param wxPayService + * @param isIsvsubMch + * @param tradeType + * @param wxCallBack + * @Return: java.lang.String + * @Author: terrfly + * @Date: 2022/4/25 12:38 + */ + public static String commonReqWx(WxpayV3OrderRequestModel model, WxPayService wxPayService, boolean isIsvsubMch, String tradeType, WxCallBack wxCallBack) throws WxPayException { + + // 请求地址 + String reqUrl = PAY_BASE_URL + NORMALMCH_URL_MAP.get(tradeType); + if(isIsvsubMch){ // 特约商户 + reqUrl = PAY_BASE_URL + ISV_URL_MAP.get(tradeType); + } + + // 调起http请求 + String response = wxPayService.postV3(reqUrl, JSON.toJSONString(model)); + + JSONObject wxRes = JSON.parseObject(response); + + if(wxCallBack != null){ + return wxCallBack.genPayInfo(wxRes); + } + + return response; + } + + + public static JSONObject queryOrderV3(String url, WxPayService wxPayService) throws WxPayException { + String response = wxPayService.getV3(PAY_BASE_URL + url); + return JSON.parseObject(response); + } + + public static JSONObject closeOrderV3(String url, JSONObject reqJSON, WxPayService wxPayService) throws WxPayException { + String response = wxPayService.postV3(PAY_BASE_URL + url, reqJSON.toJSONString()); + return JSON.parseObject(response); + } + + public static JSONObject refundV3(JSONObject reqJSON, WxPayService wxPayService) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds", PAY_BASE_URL); + String response = wxPayService.postV3(url, reqJSON.toJSONString()); + return JSON.parseObject(response); + } + + public static JSONObject refundQueryV3(String refundOrderId, WxPayService wxPayService) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds/%s", PAY_BASE_URL, refundOrderId); + String response = wxPayService.getV3(url); + return JSON.parseObject(response); + } + + public static JSONObject refundQueryV3Isv(String refundOrderId, WxPayService wxPayService, String subMchId) throws WxPayException { + String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", PAY_BASE_URL, refundOrderId, subMchId); + String response = wxPayService.getV3(url); + return JSON.parseObject(response); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/model/WxpayV3OrderRequestModel.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/model/WxpayV3OrderRequestModel.java new file mode 100644 index 0000000..f773d54 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/model/WxpayV3OrderRequestModel.java @@ -0,0 +1,151 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.model; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; +import lombok.experimental.Accessors; + +/** +* +* 微信V3支付请求参数类 +* @author terrfly +* +* @date 2022/4/25 11:52 +*/ +@Data +@Accessors(chain = true) +public class WxpayV3OrderRequestModel { + + /** 服务商应用ID */ + @JSONField(name = "sp_appid") + private String spAppid; + + /** 服务商户号 */ + @JSONField(name = "sp_mchid") + private String spMchid; + + /** 子商户号 */ + @JSONField(name = "sub_mchid") + private String subMchid; + + /** 子商户应用ID */ + @JSONField(name = "sub_appid") + private String subAppid; + + /** 普通商户: 商户号 */ + @JSONField(name = "mchid") + private String normalMchid; + + /** 普通商户: appId */ + @JSONField(name = "appid") + private String normalAppid; + + /** 商户订单号 */ + @JSONField(name = "out_trade_no") + private String outTradeNo; + + /** 商品描述 */ + private String description; + + /** 交易结束时间 */ + @JSONField(name = "time_expire") + private String timeExpire; + + /** 附加数据 */ + private String attach; + + /** 通知地址 */ + @JSONField(name = "notify_url") + private String notifyUrl; + + /** 订单优惠标记 */ + @JSONField(name = "goods_tag") + private String goodsTag; + + /** 结算信息 */ + @JSONField(name = "settle_info") + private SettleInfo settleInfo; + + /** 订单金额 */ + private Amount amount; + + /** 支付者 */ + private Payer payer; + + /** 场景信息 */ + @JSONField(name = "scene_info") + private SceneInfo sceneInfo; + + /** 场景信息 **/ + @Data + @Accessors(chain = true) + public static class SceneInfo{ + + /** 用户终端IP */ + @JSONField(name = "payer_client_ip") + private String payerClientIp; + + /** 商户端设备号 */ + @JSONField(name = "device_id") + private String deviceId; + + /** 商户端设备号 */ + @JSONField(name = "h5_info") + private H5Info h5Info; + + /** H5场景信息 */ + @Data + @Accessors(chain = true) + public static class H5Info{ + + /** 场景类型 */ + @JSONField(name = "type") + private String type; + + } + + } + + + /** 结算信息 **/ + @Data + @Accessors(chain = true) + public static class SettleInfo{ + + /** 用户服务标识 */ + @JSONField(name = "profit_sharing") + private Boolean profitSharing; + + } + + + /** 支付者 **/ + @Data + @Accessors(chain = true) + public static class Payer{ + + /** 普通商户的: 用户服务标识 */ + @JSONField(name = "openid") + private String normalOpenId; + + /** 用户服务标识 */ + @JSONField(name = "sp_openid") + private String spOpenid; + + /** 用户子标识 */ + @JSONField(name = "sub_openid") + private String subOpenid; + } + + /** 订单金额 **/ + @Data + @Accessors(chain = true) + public static class Amount{ + + /** 总金额 */ + private Integer total; + + /** 货币类似 */ + private String currency; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxApp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxApp.java new file mode 100644 index 0000000..2e332ef --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxApp.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxAppOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 微信 app支付 +* +* @author zhuxiao +* +* @date 2021/6/8 18:08 +*/ +@Service("wxpayPaymentByAppService") //Service Name需保持全局唯一性 +public class WxApp extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext); + req.setTradeType(WxPayConstants.TradeType.APP); + + // 重新设置 微信app支付 appId参数 + if(mchAppConfigContext.isIsvsubMch()){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + req.setSubAppId(isvsubMchParams.getSubMchOpenAppId()); + + }else { + + WxpayNormalMchParams normalMchParams = (WxpayNormalMchParams) configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + req.setAppid(normalMchParams.getOpenAppId()); + + } + + // 构造函数响应数据 + WxAppOrderRS res = ApiResBuilder.buildSuccess(WxAppOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + try { + WxPayAppOrderResult payResult = wxPayService.createOrder(req); + JSONObject resJSON = (JSONObject) JSON.toJSON(payResult); + resJSON.put("package", payResult.getPackageValue()); + + res.setPayData(resJSON.toJSONString()); + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxBar.java new file mode 100644 index 0000000..592c80c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxBar.java @@ -0,0 +1,102 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + + +import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; +import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 微信 bar + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByBarService") //Service Name需保持全局唯一性 +public class WxBar extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + + // 微信统一下单请求对象 + WxPayMicropayRequest request = new WxPayMicropayRequest(); + request.setOutTradeNo(payOrder.getPayOrderId()); + request.setBody(payOrder.getSubject()); + request.setDetail(payOrder.getBody()); + request.setFeeType("CNY"); + request.setTotalFee(payOrder.getFindAmt().intValue()); + request.setSpbillCreateIp(payOrder.getClientIp()); + request.setAuthCode(bizRQ.getAuthCode().trim()); + + //订单分账, 将冻结商户资金。 + if(isDivisionOrder(payOrder)){ + request.setProfitSharing("Y"); + } + + //放置isv信息 + WxpayKit.putApiIsvInfo(mchAppConfigContext, request); + + // 构造函数响应数据 + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + try { + WxPayMicropayResult wxPayMicropayResult = wxPayService.micropay(request); + + channelRetMsg.setChannelOrderId(wxPayMicropayResult.getTransactionId()); + channelRetMsg.setChannelUserId(wxPayMicropayResult.getOpenid()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setPlatformOrderNo(wxPayMicropayResult.getTransactionId()); + channelRetMsg.setPlatformMchOrderNo(payOrder.getPayOrderId()); + + } catch (WxPayException e) { + //微信返回支付状态为【支付结果未知】, 需进行查单操作 + if("SYSTEMERROR".equals(e.getErrCode()) || "USERPAYING".equals(e.getErrCode()) || "BANKERROR".equals(e.getErrCode())){ + + //轮询查询订单 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + channelRetMsg.setNeedQuery(true); + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxH5.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxH5.java new file mode 100644 index 0000000..24cdd60 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxH5.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.net.URLEncodeUtil; +import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxH5OrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxH5OrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* + * 微信 H5 支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByH5Service") //Service Name需保持全局唯一性 +public class WxH5 extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + WxH5OrderRQ bizRQ = (WxH5OrderRQ) rq; + + WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext); + req.setTradeType(WxPayConstants.TradeType.MWEB); + + // 构造函数响应数据 + WxH5OrderRS res = ApiResBuilder.buildSuccess(WxH5OrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + try { + WxPayMwebOrderResult wxPayMwebOrderResult = wxPayService.createOrder(req); + + // 拼接returnUrl + String payUrl = String.format("%s&redirect_url=%s", wxPayMwebOrderResult.getMwebUrl(), URLEncodeUtil.encode(getReturnUrlOnlyJump(payOrder.getPayOrderId()))); + + payUrl = String.format("%s/api/common/payUrl/%s", sysConfigService.getDBApplicationConfig().getPaySiteUrl(), Base64.encode(payUrl)); + + if(CS.PAY_DATA_TYPE.FORM.equals(bizRQ.getPayDataType())){ //表单方式 + res.setFormContent(payUrl); + }else if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(payUrl)); + }else{ // 默认都为 payUrl方式 + res.setPayUrl(payUrl); + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxJsapi.java new file mode 100644 index 0000000..8c2af82 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxJsapi.java @@ -0,0 +1,117 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 微信 jsapi支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByJsapiService") //Service Name需保持全局唯一性 +@Slf4j +public class WxJsapi extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openid]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + + WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext); + req.setTradeType(WxPayConstants.TradeType.JSAPI); + + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()) { + + // 明确使用的 subMchAppId 获取到的openId + if(bizRQ.getIsSubOpenId() != null && bizRQ.getIsSubOpenId() == CS.YES){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + req.setSubAppId(isvsubMchParams.getSubMchAppId()); + req.setSubOpenid(bizRQ.getOpenid()); + + }else if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ // 使用参数传递的appID + + req.setSubAppId(bizRQ.getSubAppid()); + req.setSubOpenid(bizRQ.getOpenid()); + + }else{ // 使用的服务商配置的公众号appId获取 + + // appId就是使用默认的 + req.setOpenid(bizRQ.getOpenid()); + } + + }else{ //普通商户 设置openId即可。 + + req.setOpenid(bizRQ.getOpenid()); // 用户在子商户appid下的唯一标识 + + } + + // 构造函数响应数据 + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + try { + WxPayMpOrderResult payResult = wxPayService.createOrder(req); + JSONObject resJSON = (JSONObject) JSON.toJSON(payResult); + resJSON.put("package", payResult.getPackageValue()); + + res.setPayInfo(resJSON.toJSONString()); + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + log.error("WxPayException:", e); + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxLite.java new file mode 100644 index 0000000..09d17e6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxLite.java @@ -0,0 +1,123 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 微信 小程序支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByLiteService") //Service Name需保持全局唯一性 +@Slf4j +public class WxLite extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openid]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + + WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext); + req.setTradeType(WxPayConstants.TradeType.JSAPI); + + // 构造函数响应数据 + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()) { + + // 注意: 服务商模式调用小程序支付: 无法获取到openId参数, 只能是subOpenId参数的传入 + + // 明确使用的 subMchLiteAppId 获取到的openId + if(bizRQ.getIsSubOpenId() != null && bizRQ.getIsSubOpenId() == CS.YES){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + req.setSubAppId(isvsubMchParams.getSubMchLiteAppId()); + req.setSubOpenid(bizRQ.getOpenid()); + + }else if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ // 使用参数传递的appID + + req.setSubAppId(bizRQ.getSubAppid()); + req.setSubOpenid(bizRQ.getOpenid()); + + }else{ // 使用的服务商配置的小程序appId获取 + + req.setSubAppId(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid()); + req.setSubOpenid(bizRQ.getOpenid()); + } + + }else{ // 普通商户 + + // 如果配置了小程序的appId, 那么需要传入到这里 + if(wxServiceWrapper.getWxMaService() != null && wxServiceWrapper.getWxMaService().getWxMaConfig() != null && StringUtils.isNotBlank(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid())){ + req.setAppid(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid()); + }else{ + + // 没有配置小程序的appId, 那么默认使用的 支付配置的appId + } + + //openId + req.setOpenid(bizRQ.getOpenid()); + } + + try { + WxPayMpOrderResult payResult = wxPayService.createOrder(req); + JSONObject resJSON = (JSONObject) JSON.toJSON(payResult); + resJSON.put("package", payResult.getPackageValue()); + + res.setPayInfo(resJSON.toJSONString()); + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxNative.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxNative.java new file mode 100644 index 0000000..d40187f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/payway/WxNative.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.payway; + +import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxNativeOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxNativeOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* + * 微信 native支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByNativeService") //Service Name需保持全局唯一性 +public class WxNative extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxNativeOrderRQ bizRQ = (WxNativeOrderRQ) rq; + + WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext); + req.setTradeType(WxPayConstants.TradeType.NATIVE); + + // 构造函数响应数据 + WxNativeOrderRS res = ApiResBuilder.buildSuccess(WxNativeOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + // 1. 如果抛异常,则订单状态为: 生成状态,此时没有查单处理操作。 订单将超时关闭 + // 2. 接口调用成功, 后续异常需进行捕捉, 如果 逻辑代码出现异常则需要走完正常流程,此时订单状态为: 支付中, 需要查单处理。 + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + try { + WxPayNativeOrderResult wxPayNativeOrderResult = wxPayService.createOrder(req); + + String codeUrl = wxPayNativeOrderResult.getCodeUrl(); + if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(codeUrl)); + }else{ + + res.setCodeUrl(codeUrl); + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxApp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxApp.java new file mode 100644 index 0000000..51a8d38 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxApp.java @@ -0,0 +1,134 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.util.PemUtils; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxAppOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/* + * 微信 app支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByAppV3Service") //Service Name需保持全局唯一性 +public class WxApp extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 构造请求数据 + WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext); + + // 添加子商户参数 + if(mchAppConfigContext.isIsvsubMch()){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + wxpayV3OrderRequestModel.setSubAppid(isvsubMchParams.getSubMchOpenAppId()); + + }else { + + WxpayNormalMchParams normalMchParams = (WxpayNormalMchParams) configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + wxpayV3OrderRequestModel.setNormalAppid(normalMchParams.getOpenAppId()); + + } + + // 构造函数响应数据 + WxAppOrderRS res = ApiResBuilder.buildSuccess(WxAppOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + try { + String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.APP, + (JSONObject wxRes) -> { + + // 普通商户,App支付与公众号支付 同一个应用只能配置其中一个 + String resultAppId = wxpayV3OrderRequestModel.getNormalAppid(); + String resultMchId = wxpayV3OrderRequestModel.getNormalMchid(); + + // 特约商户,App支付与公众号支付 同一个应用只能配置其中一个 + if(mchAppConfigContext.isIsvsubMch()){ + resultAppId = wxpayV3OrderRequestModel.getSubAppid(); + resultMchId = wxpayV3OrderRequestModel.getSubMchid(); + } + + WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result(); + wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id")); + + try { + + FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath()); + + WxPayUnifiedOrderV3Result.AppResult appResult = + wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.APP, resultAppId, resultMchId, + PemUtils.loadPrivateKey(fis)); + + JSONObject jsonRes = (JSONObject)JSON.toJSON(appResult); + jsonRes.put("package", jsonRes.getString("packageValue")); + jsonRes.remove("packageValue"); + + try { + fis.close(); + } catch (IOException e) { + } + + return JSON.toJSONString(jsonRes); + + } catch (FileNotFoundException e) { + + return null; + + } + } + ); + + res.setPayData(payInfo); + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxBar.java new file mode 100644 index 0000000..122671d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxBar.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + + +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; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* + * 微信 条码支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByBarV3Service") //Service Name需保持全局唯一性 +public class WxBar extends WxpayPaymentService { + + @Autowired + private com.jeequan.jeepay.thirdparty.channel.wxpay.payway.WxBar wxBar; + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return wxBar.preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return wxBar.pay(rq, payOrder, mchAppConfigContext); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxH5.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxH5.java new file mode 100644 index 0000000..4f92072 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxH5.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.net.URLEncodeUtil; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxH5OrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxH5OrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* + * 微信 H5支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByH5V3Service") //Service Name需保持全局唯一性 +public class WxH5 extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + WxH5OrderRQ bizRQ = (WxH5OrderRQ) rq; + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 构造请求数据 + WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext); + + // 场景信息 + wxpayV3OrderRequestModel.getSceneInfo().setH5Info(new WxpayV3OrderRequestModel.SceneInfo.H5Info().setType("iOS, Android, Wap")); + + // 构造函数响应数据 + WxH5OrderRS res = ApiResBuilder.buildSuccess(WxH5OrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + try { + String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.MWEB, null); + + JSONObject resJSON = JSONObject.parseObject(payInfo); + + // 拼接returnUrl + String payUrl = String.format("%s&redirect_url=%s", resJSON.getString("h5_url"), URLEncodeUtil.encode(getReturnUrlOnlyJump(payOrder.getPayOrderId()))); + + payUrl = String.format("%s/api/common/payUrl/%s", sysConfigService.getDBApplicationConfig().getPaySiteUrl(), Base64.encode(payUrl)); + + if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(payUrl)); + }else{ // 默认都为 payUrl方式 + res.setPayUrl(payUrl); + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxJsapi.java new file mode 100644 index 0000000..2840a91 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxJsapi.java @@ -0,0 +1,156 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.util.PemUtils; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/* + * 微信 jsapi支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByJsapiV3Service") //Service Name需保持全局唯一性 +public class WxJsapi extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + // 使用的是V2接口的预先校验 + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + + // 获取微信service (V2可直接使用) + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + + // 构造请求数据 ( 通用 ) + WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext); + + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()) { + + // 明确使用的 subMchAppId 获取到的openId + if(bizRQ.getIsSubOpenId() != null && bizRQ.getIsSubOpenId() == CS.YES){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + wxpayV3OrderRequestModel.setSubAppid(isvsubMchParams.getSubMchAppId()); + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); + + }else if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ // 使用参数传递的appID + + wxpayV3OrderRequestModel.setSubAppid(bizRQ.getSubAppid()); + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); + + }else{ // 使用的服务商配置的公众号appId获取 + + // appId就是使用默认的 + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSpOpenid(bizRQ.getOpenid())); + } + + }else{ //普通商户 设置openId即可。 + + //openId + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setNormalOpenId(bizRQ.getOpenid())); + + } + + // 构造函数响应数据 + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + + // 调起上游接口: + try { + + // 调起接口 modify 20220425 by terrfly : 改为统一调用的方式, 将返回数据包放置在业务层进行处理 。 + String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.JSAPI, + (JSONObject wxRes) -> { + + // 普通商户 + String resultAppId = wxpayV3OrderRequestModel.getNormalAppid(); + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + resultAppId = StringUtils.defaultIfEmpty(wxpayV3OrderRequestModel.getSubAppid(), wxpayV3OrderRequestModel.getSpAppid()); + } + + WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result(); + wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id")); + try { + + FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath()); + + WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = + wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.JSAPI, resultAppId, null, + PemUtils.loadPrivateKey(fis)); + + JSONObject jsonRes = (JSONObject)JSON.toJSON(jsapiResult); + jsonRes.put("package", jsonRes.getString("packageValue")); + jsonRes.remove("packageValue"); + + try { + fis.close(); + } catch (IOException e) { + } + + return JSON.toJSONString(jsonRes); + + } catch (FileNotFoundException e) { + return null; + + } + } + ); + + // 返回包装数据 + res.setPayInfo(payInfo); + + } catch (WxPayException e) { + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + return res; + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxLite.java new file mode 100644 index 0000000..a462560 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxLite.java @@ -0,0 +1,169 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.v3.util.PemUtils; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/* + * 微信 小程序 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Slf4j +@Service("wxpayPaymentByLiteV3Service") //Service Name需保持全局唯一性 +public class WxLite extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + // 使用的是V2接口的预先校验 + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + + // 获取微信service (V2可直接使用) + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + + // 构造请求数据 ( 通用 ) + WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext); + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()) { + + // 注意: 服务商模式调用小程序支付: 无法获取到openId参数, 只能是subOpenId参数的传入 + + // 明确使用的 subMchLiteAppId 获取到的openId + if(bizRQ.getIsSubOpenId() != null && bizRQ.getIsSubOpenId() == CS.YES){ + + WxpayIsvsubMchParams isvsubMchParams = (WxpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + + wxpayV3OrderRequestModel.setSubAppid(isvsubMchParams.getSubMchLiteAppId()); + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); + + + }else if(StringUtils.isNotEmpty(bizRQ.getSubAppid())){ // 使用参数传递的appID + + wxpayV3OrderRequestModel.setSubAppid(bizRQ.getSubAppid()); + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); + + }else{ // 使用的服务商配置的小程序appId获取 + + wxpayV3OrderRequestModel.setSubAppid(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid()); + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setSubOpenid(bizRQ.getOpenid())); + + } + + }else{ // 普通商户 + + // 如果配置了小程序的appId, 那么需要传入到这里 + if(wxServiceWrapper.getWxMaService() != null && wxServiceWrapper.getWxMaService().getWxMaConfig() != null && StringUtils.isNotBlank(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid())){ + wxpayV3OrderRequestModel.setNormalAppid(wxServiceWrapper.getWxMaService().getWxMaConfig().getAppid()); + }else{ + + // 没有配置小程序的appId, 那么默认使用的 支付配置的appId + } + //openId + wxpayV3OrderRequestModel.setPayer(new WxpayV3OrderRequestModel.Payer().setNormalOpenId(bizRQ.getOpenid())); + } + + + // 构造函数响应数据 + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + + // 调起上游接口: + try { + + // 调起接口 modify 20220425 by terrfly : 改为统一调用的方式, 将返回数据包放置在业务层进行处理 。 + String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.JSAPI, + (JSONObject wxRes) -> { + + // 普通商户 + String resultAppId = wxpayV3OrderRequestModel.getNormalAppid(); + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + resultAppId = StringUtils.defaultIfEmpty(wxpayV3OrderRequestModel.getSubAppid(), wxpayV3OrderRequestModel.getSpAppid()); + } + + // 使用wxjava公共函数,生成 + WxPayUnifiedOrderV3Result wxPayUnifiedOrderV3Result = new WxPayUnifiedOrderV3Result(); + wxPayUnifiedOrderV3Result.setPrepayId(wxRes.getString("prepay_id")); + try { + + FileInputStream fis = new FileInputStream(wxPayService.getConfig().getPrivateKeyPath()); + + WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = + wxPayUnifiedOrderV3Result.getPayInfo(TradeTypeEnum.JSAPI, resultAppId, null, + PemUtils.loadPrivateKey(fis)); + + JSONObject jsonRes = (JSONObject)JSON.toJSON(jsapiResult); + jsonRes.put("package", jsonRes.getString("packageValue")); + jsonRes.remove("packageValue"); + + try { + fis.close(); + } catch (IOException e) { + } + + return JSON.toJSONString(jsonRes); + + } catch (FileNotFoundException e) { + return null; + + } + } + ); + + // 返回包装数据 + res.setPayInfo(payInfo); + + } catch (WxPayException e) { + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + return res; + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxNative.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxNative.java new file mode 100644 index 0000000..34d44ec --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/wxpay/paywayV3/WxNative.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel.wxpay.paywayV3; + +import com.alibaba.fastjson.JSONObject; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxNativeOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxNativeOrderRS; +import com.jeequan.jeepay.thirdparty.channel.wxpay.WxpayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayKit; +import com.jeequan.jeepay.thirdparty.channel.wxpay.kits.WxpayV3Util; +import com.jeequan.jeepay.thirdparty.channel.wxpay.model.WxpayV3OrderRequestModel; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* + * 微信 native支付 + * + * @author zhuxiao + * + * @date 2021/6/8 18:08 + */ +@Service("wxpayPaymentByNativeV3Service") //Service Name需保持全局唯一性 +public class WxNative extends WxpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + + WxNativeOrderRQ bizRQ = (WxNativeOrderRQ) rq; + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext); + WxPayService wxPayService = wxServiceWrapper.getWxPayService(); + + // 构造请求数据 + WxpayV3OrderRequestModel wxpayV3OrderRequestModel = buildV3OrderRequestModel(payOrder, mchAppConfigContext); + + // 构造函数响应数据 + WxNativeOrderRS res = ApiResBuilder.buildSuccess(WxNativeOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + // 调起上游接口: + try { + String payInfo = WxpayV3Util.commonReqWx(wxpayV3OrderRequestModel, wxPayService, mchAppConfigContext.isIsvsubMch(), WxPayConstants.TradeType.NATIVE, null); + + JSONObject resJSON = JSONObject.parseObject(payInfo); + String codeUrl = resJSON.getString("code_url"); + if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(codeUrl)); + }else{ + + res.setCodeUrl(codeUrl); + } + + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + } catch (WxPayException e) { + //明确失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + WxpayKit.commonSetErrInfo(channelRetMsg, e); + } + + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/YbpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/YbpayKit.java new file mode 100644 index 0000000..3516c50 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/YbpayKit.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.thirdparty.channel.ybpay; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.params.ybpay.YbpayIsvParams; +import com.jeequan.jeepay.thirdparty.channel.ybpay.model.ReqHeader; +import com.jeequan.jeepay.thirdparty.channel.ybpay.model.ReqMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; + +import java.util.Map; + +/** + * TODO + * 易宝kit + * @author crystal + * @date 2024/2/27 11:01 + */ +@Slf4j +public class YbpayKit { + + /** + * 发起请求 返回业务参数 + * + * @param method + * @param reqData + * @return + */ + public static JSONObject reqApi(ReqMethod.Method method, YbpayIsvParams isvParams, JSONObject reqData) { + ReqHeader header = new ReqHeader(isvParams); + Map headers = header.toHeader(isvParams,method); + HttpResponse response = HttpRequest.post(ReqMethod.getUrl(method)).headerMap(headers, false).body(reqData.toString()).execute(); + if(HttpStatus.OK.value() != response.getStatus()){ + throw new BizException("接口请求异常"); + } + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqHeader.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqHeader.java new file mode 100644 index 0000000..59e8c08 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqHeader.java @@ -0,0 +1,112 @@ +package com.jeequan.jeepay.thirdparty.channel.ybpay.model; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.SM2; +import com.jeequan.jeepay.core.model.params.ybpay.YbpayIsvParams; +import lombok.Getter; +import lombok.Setter; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * TODO + * 易宝 请求头参数 + * @author crystal + * @date 2024/4/26 14:17 + */ +@Getter +@Setter +public class ReqHeader { + + public static final String SECURITY_REQ = "YOP-RSA2048-SHA256"; + + public static final String AUTH_STR = "yop-auth-v3"; + + public static final String CONTENT_TYPE = "application/x-www-form-urlencoded; charset=UTF-8"; + + public static final String DEFAULT_VERSION = "4.0.0"; + + public static final String SIGN_HEADER = "content-type;x-yop-appkey;x-yop-content-sha256;x-yop-request-id"; + + /** + * 鉴权认证串 Authorization + */ + private String authorization; + + /** + * 请求唯一流水号 + * x-yop-request-id + */ + private String requestId; + + /** + * 请求appid + * x-yop-appkey + */ + private String appid; + + /** + * 请求content-type + * Content-Type + */ + private String contentType; + + /** + * 语言(如:java/python/go) + * x-yop-sdk-langs + */ + private String language; + + /** + * 自实现目前统一使用 4.0.0 + */ + private String version; + + /** + * 摘要 + */ + private String keyContent; + + + public ReqHeader(YbpayIsvParams isvParams) { + this.requestId = IdUtil.fastUUID(); + this.appid = isvParams.getAppId(); + this.contentType = CONTENT_TYPE; + this.version = DEFAULT_VERSION; + this.keyContent = isvParams.getKeyContent(); + this.language = "java"; + } + + public Map toHeader(YbpayIsvParams isvParams,ReqMethod.Method method) { + Map headers = new HashMap<>(6); + headers.put("x-yop-request-id",this.getRequestId()); + headers.put("x-yop-appkey",this.getAppid()); + headers.put("Content-Type",this.getContentType()); + headers.put("x-yop-sdk-langs",this.getLanguage()); + headers.put("x-yop-sdk-version",this.getVersion()); + headers.put("x-yop-content-sm3",this.getKeyContent()); + String authString = AUTH_STR + "/" + this.getAppid() + "/" + DateUtil.format(new DateTime(), "yyyy-MM-dd'T'HH:mm:ss'Z'") + "/1800"; + String Authorization = SECURITY_REQ + " " + authString + "/" + SIGN_HEADER + "/" + genSign(isvParams,authString,method); + headers.put("Authorization",Authorization); + return headers; + } + + /** + * + * @param isvParams + * @param authString + * @param method + * @return + */ + private String genSign(YbpayIsvParams isvParams,String authString,ReqMethod.Method method) { + SM2 sm2 = SmUtil.sm2(isvParams.getPrivateKey(), isvParams.getPublicKey()); + String signContent = authString + "\n" + method.getReqType() + "\n" + method.getMethod() + "\n" ; + return Base64.getEncoder().encodeToString(sm2.sign(signContent.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqMethod.java new file mode 100644 index 0000000..ec023a8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/ybpay/model/ReqMethod.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.ybpay.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2024/2/27 11:52 + */ +@Data +public class ReqMethod { + + /** + * 统一请求域名 + */ + private final static String DOMAIN = ""; + + + @Getter + @AllArgsConstructor + public enum Method{ + + PRE_PAY("/rest/v1.0/aggpay/pre-pay","POST","微信认证"), + ; + + private final String method; + + private final String reqType; + + private final String desc; + + } + + /** + * 获取请求接口地址 + * @param method + * @return + */ + public static String getUrl(Method method){ + return DOMAIN + method.getMethod(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentApiService.java new file mode 100644 index 0000000..e113365 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentApiService.java @@ -0,0 +1,687 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.BaseConverter; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IYsApplymentApiService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.applyment.YspayApplymentInfo; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.JsonKit; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * 银盛进件 + * + * + * @date 2022/7/18 14:30 + */ +@Service +@Slf4j +public class YspayApplymentApiService implements IYsApplymentApiService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private BaseConverter baseConverter; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchModifyApplymentService mchModifyApplymentService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + /** + * @author: xiaoyu + * @date: 2022/7/20 11:02 + * @describe: 图片上传接口 + */ + @Override + public MchApplyment uploadImg(MchApplyment mchApplyment) { + + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + + // 获取详细参数 + YspayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), YspayApplymentInfo.class); + + try { + JSONArray uploadArr = new JSONArray(); + // 进件渠道号 + String applyNo = mchApplyment.getChannelApplyNo(); + + // 非小微商户必填 + if (applymentInfo.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + // 营业执照 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getLicenseImg(), "A001")); + } + // 法人身份证人像面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getIdcard1Img(), "A002")); + // 法人身份证国徽面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getIdcard2Img(), "A003")); + // 手持身份证照 +// setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getIdcardInHandImg(), "A009")); + + // 非小微或企业非对私 + if (MchApplyment.MERCHANT_TYPE_PERSONAL != applymentInfo.getMerchantType() && !"C".equals(applymentInfo.getSettAccountType())) { + // 开户许可证 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getCompanyAccountLicenseImg(), "A011")); + } else { + // 结算账户正面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettAccountLicenseImg(), "A004")); + // 结算账户反面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettAccountLicenseImg(), "A005")); + } + + if ("Y".equals(applymentInfo.getIsUncrpSett())) { + // 非法人身份证人像面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettAccountIdcard1Img(), "A013")); + // 非法人身份证国徽面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettAccountIdcard2Img(), "A014")); + // 结算授权书 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettleAuthLetterPhoto(), "B005")); + // 法人手持结算授权书 +// setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getSettleAuthLetterHandlePhoto(), "B004")); + } else { + // 法人身份证人像面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getIdcard1Img(), "A013")); + // 法人身份证国徽面 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getIdcard2Img(), "A014")); + } + + // 门头照 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getStoreOuterImg(), "A006")); + // 内景照 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getStoreInnerImg(), "A007")); + // 收银台照 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getStoreCashierImg(), "A008")); + // 收单协议照 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getAcquiringAgreementPhoto(), "A010")); + // 其他1 + setArrImgResult(uploadArr, YspayKit.uploadRequest(applyNo, isvParams, applymentInfo.getOther1(), "B008")); + + // 上传图片结果 +// result.setChannelVar1(uploadArr.toJSONString()); + result.setApplyDetailInfo(mchApplyment.getApplyDetailInfo()); + return result; + } catch (Exception e) { + log.error("银盛进件失败:", e); + throw new BizException(e.getMessage()); + } + } + + /** + * @date: 2022/7/19 16:27 + * @describe: 图片存放 + */ + private static void setArrImgResult(JSONArray arrayImg, JSONObject params) { + if (params != null) { + arrayImg.add(params); + } + } + + /** + * @date: 2022/7/20 11:02 + * @describe: 提交初审 + */ + @Override + public MchApplyment attachConfirm(MchApplyment mchApplyment) { + + // 获取到 渠道商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + MchApplyment result = new MchApplyment(); + result.setState(mchApplyment.getState()); + + try { + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContent.put("sysFlowId", mchApplyment.getChannelApplyNo()); + bizContent.put("auditFlag", "Y"); + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/t1/smsc/auditCustInfoApply", "t1.smsc.auditCustInfoApply", isvParams, bizContent); + JSONObject response = JSON.parseObject(resultStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(response.getString("code") + "[" + response.getString("note") + "]"); + log.error("【银盛进件】提交审核请求失败:code={}, msg={}", response.getString("code"), response.getString("note")); + return result; + } + + // 入网状态,00:入网成功 01:待上传图片 02:待审核 90:审核拒绝 10:转人工审核 + String status = resData.getString("status"); + if ("00".equals(status)) { + // 留给异步处理 + return mchApplyment; + } else if ("01".equals(status)) { + JSONObject sucJSON = JsonKit.newJson("custId", resData.getString("custId")); + sucJSON.put("sysFlowId", resData.getString("sysFlowId")); + result.setSuccResParameter(sucJSON.toJSONString()); + result.setRemainStep(((byte) 2)); + result.setState(MchApplyment.STATE_WAIT_VERIFY); + return result; + } else if ("10".equals(status)) { + // 转人工审核 + result.setState(MchApplyment.STATE_UPSTREAM_MANUAL_REVIEW); + result.setApplyErrorInfo("[" + resData.getString("note") + "]"); + result.setRemainStep((byte) 0); + return result; + } else if ("90".equals(status)) { + // 审核拒绝 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + resData.getString("note") + "]"); + result.setRemainStep((byte) 0); + return result; + } else { + result.setApplyErrorInfo("[" + resData.getString("note") + "]"); + return result; + } + + } catch (BizException e) { + if (e.getApiRes().getCode().equals(ApiCodeEnum.YS_ARTIFICIAL_AUDIT_CODE.getCode())) { + // 转人工审核 + result.setState(MchApplyment.STATE_UPSTREAM_MANUAL_REVIEW); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + result.setRemainStep((byte) 0); + return result; + } else { + throw e; + } + } catch (Exception e) { + log.error("银盛进件失败:", e); + throw new BizException(e.getMessage()); + } + } + + + /** + * @date: 2022/7/21 10:23 + * @describe: 费率配置 + */ + @Override + public MchApplyment signApply(JSONObject reqParamJSON, MchApplyment record) { + + MchApplyment result = new MchApplyment(); + ApplymentSignInfo signInfo = new ApplymentSignInfo(); + + try { + // 费率信息 + List paywayFeeList = JSON.parseArray(reqParamJSON.getString("paywayFeeList"), PaywayFee.class); + + // 获取到 渠道商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(record); + + JSONObject channelVar1 = JSON.parseObject(record.getChannelVar1()); + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("custId", channelVar1.getString("custId")); + bizContent.put("contractType", "2"); // 合同类型,1-纸质合同、2-电子合同 + bizContent.put("isSendConMsg", "1"); // 是否自动发送签约通知, contractType=2时必填 0(短信+邮件) 1(短信) 2(邮件) 3(不通知) + // 异步通知地址,这里将channelApplyNo传进去,方便签约回调时好找到商户信息 + bizContent.put("notifyUrl", sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + record.getIfCode() + "/" + record.getApplyId()); + +// bizContent.put("busOpenType", "00"); // 到账方式,00-扫码工作日到账 + bizContent.put("codeScanT1Fee", YspayApplymentInfo.convertFeeJSON(paywayFeeList, "1")); + // 结算方式 1- T1 2-D1 3-D0 +// bizContent.put("d1Fee", YspayApplymentInfo.convertFeeJSON(paywayFeeList, "2")); + // 开通D0, 支付时可通过接口传参来选择D1、D0支付方式 + // 00-(T1)扫码工作日到账,01-(D0)扫码实时到账,20-天天到账,D1到账 + bizContent.put("busOpenType", "00|01"); // 到账方式,01-扫码实时到账 + bizContent.put("codeScanD0Fee", YspayApplymentInfo.convertFeeJSON(paywayFeeList, "3")); + + // 发送请求 + String resStr = YspayKit.applymentRequest("/openapi/t1/smsc/sign", "t1.smsc.sign", isvParams, bizContent); + JSONObject response = JSON.parseObject(resStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + signInfo.setErrInfo(response.getString("code") + "[" + response.getString("note") + "]"); + log.error("【银盛进件】提交审核请求失败:code={}, msg={}", response.getString("code"), response.getString("note")); + result.setChannelVar2(JSON.toJSONString(signInfo)); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return result; + } + + signInfo.setSignUrl(resData.getString("signUrl")); + signInfo.setState("签约中"); + signInfo.setOriginData(resData.toJSONString()); + + result.setChannelVar2(JSON.toJSONString(signInfo)); + + // 费率信息 + JSONObject applyDetailJSON = JSON.parseObject(record.getApplyDetailInfo()); + applyDetailJSON.put("paywayFeeList", paywayFeeList); + result.setApplyDetailInfo(applyDetailJSON.toJSONString()); + result.setState(MchApplyment.STATE_WAIT_SIGN); + + return result; + + } catch (Exception e) { + log.info("签约异常", e); + throw new BizException("签约异常[" + e.getMessage() + "]"); + } + } + + @Override + public MchApplyment signSendAgain(JSONObject reqParamJSON, MchApplyment mchApplyment) { + + MchApplyment result = new MchApplyment(); + ApplymentSignInfo signInfo = new ApplymentSignInfo(); + + try { + + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + if (StringUtils.isEmpty(mchApplyment.getChannelVar2())) { + log.error("【银盛进件】签约重发失败,签约参数缺失:{}", mchApplyment.getChannelVar2()); + signInfo.setErrInfo("签约重发失败,签约参数缺失"); + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + } + JSONObject channelV2Json = JSON.parseObject(mchApplyment.getChannelVar2()); + JSONObject originData = channelV2Json.getJSONObject("originData"); + if (originData == null) { + log.error("【银盛进件】签约重发失败,签约参数缺失"); + signInfo.setErrInfo("签约重发失败,签约参数缺失"); + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("signId", originData.getString("signId")); + bizContent.put("isSendConMsg", "0"); + + // 发送请求 + String resStr = YspayKit.applymentRequest("/openapi/smsc/sign/sendSmsOrEmailMsg", "smsc.sign.sendSmsOrEmailMsg", isvParams, bizContent); + JSONObject response = JSON.parseObject(resStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + signInfo.setErrInfo(response.getString("code") + "[" + response.getString("note") + "]"); + log.error("【银盛进件】签约重发失败:code={}, msg={}", response.getString("code"), response.getString("note")); + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + } + signInfo.setSignUrl(resData.getString("signUrl")); + signInfo.setState("签约中"); + signInfo.setOriginData(resData.toJSONString()); + + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + + } catch (Exception e) { + log.info("签约重发异常", e); + throw new BizException("签约重发异常" + e.getMessage()); + } + } + + /** + * 获取签约地址 + */ + @Override + public MchApplyment signQuery(MchApplyment mchApplyment) { + + MchApplyment result = new MchApplyment(); + ApplymentSignInfo signInfo = new ApplymentSignInfo(); + result.setState(mchApplyment.getState()); + try { + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + // 查询数据库签约信息 + ApplymentSignInfo channelVar2Data = JSON.parseObject(mchApplyment.getChannelVar2(), ApplymentSignInfo.class); + + // 合并数据 + baseConverter.cp(channelVar2Data, signInfo); + + // 调渠道接口,查询签约状态 + JSONObject queryJSON = new JSONObject(); + JSONObject channelSignJSON = JSON.parseObject(channelVar2Data.getOriginData()); + queryJSON.put("authId", channelSignJSON.getString("authId")); + + // 发送请求 + String resStr = YspayKit.applymentRequest("/openapi/smsc/saas/constract/queryAuthInfo", "smsc.saas.constract.queryAuthInfo", isvParams, queryJSON); + JSONObject response = JSON.parseObject(resStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + signInfo.setState("签约失败"); + signInfo.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + result.setChannelVar2(JSON.toJSONString(signInfo)); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + return result; + } + + // 审核状态 + if ("00".equals(resData.getString("status"))) { + signInfo.setState("签约成功"); + // 签约完成,返回商户号 + JSONObject sucJSON = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (sucJSON == null) { + sucJSON = new JSONObject(); + } + sucJSON.put("mercId", resData.getString("mercId")); + result.setSuccResParameter(sucJSON.toJSONString()); + result.setChannelMchNo(resData.getString("mercId")); + result.setState(MchApplyment.STATE_SUCCESS); + + // TODO 银盛入网签约完成 业务大厅添加变更数据将T1变为D1并待审核 + if ("yspay".equals(mchApplyment.getIfCode())) { + MchModifyApplymentEntity modifyApplyment = new MchModifyApplymentEntity(); + modifyApplyment.setModifyApplyId(SeqKit.genMchNotifyApplyNo()); + modifyApplyment.setApplyId(mchApplyment.getApplyId()); + //modifyApplyment.setChannelApplyNo(mchApplyment.getChannelApplyNo()); + modifyApplyment.setChannelMchNo(mchApplyment.getChannelMchNo()); + modifyApplyment.setMchNo(mchApplyment.getMchNo()); + modifyApplyment.setIfCode(mchApplyment.getIfCode()); + modifyApplyment.setIfName(mchApplyment.getIfName()); + //商户本次变更前数据 + com.jeequan.jeepay.db.entity.MchApplyment applyment = mchApplymentService.getById(mchApplyment.getApplyId()); + String jsonString = JSONObject.toJSONString(applyment); + modifyApplyment.setOriginDetailInfo(jsonString); + //商户本次变更信息 + modifyApplyment.setApplyDetailInfo("{\"settlementType\":\"D1\"}"); + modifyApplyment.setApplyPageType(applyment.getApplyPageType()); + //变更类型为6 结算类型变更 + modifyApplyment.setModifyApplyType((byte) 6); + //状态默认为审核中 + modifyApplyment.setState((byte) 1); + modifyApplyment.setCreatedAt(new Date()); + mchModifyApplymentService.save(modifyApplyment); + } + } else if ("04".equals(resData.getString("status"))) { + signInfo.setState("签约失败"); + signInfo.setErrInfo(resData.getString("note")); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } else if ("03".equals(resData.getString("status"))) { + signInfo.setState("待审核"); + } else { + signInfo.setState("签约中"); + } + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + + } catch (Exception e) { + signInfo.setState("签约中"); + signInfo.setErrInfo("异常信息" + e.getMessage()); + result.setChannelVar2(JSON.toJSONString(signInfo)); + return result; + } + } + + + @Override + public MchModifyApplyment signSendAgain(JSONObject reqParamJSON, MchModifyApplyment modifyApplyment) { + + MchModifyApplyment result = new MchModifyApplyment(); + ApplymentSignInfo signInfo = new ApplymentSignInfo(); + + MchApplyment mchApplyment = mchInfoConverter.toModel(mchApplymentService.getById(modifyApplyment.getApplyId())); + + try { + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + if (StringUtils.isEmpty(modifyApplyment.getChannelVar1())) { + log.error("【银盛进件】签约重发失败,签约参数缺失:{}", mchApplyment.getChannelVar2()); + signInfo.setErrInfo("签约重发失败,签约参数缺失"); + result.setChannelVar1(JSON.toJSONString(signInfo)); + return result; + } + JSONObject channelV1Json = JSON.parseObject(modifyApplyment.getChannelVar1()); + if (channelV1Json == null) { + log.error("【银盛进件】签约重发失败,签约参数缺失"); + signInfo.setErrInfo("签约重发失败,签约参数缺失"); + result.setChannelVar1(JSON.toJSONString(signInfo)); + return result; + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("signId", channelV1Json.getString("signId")); + bizContent.put("isSendConMsg", "0"); + + // 发送请求 + String resStr = YspayKit.applymentRequest("/openapi/smsc/sign/sendSmsOrEmailMsg", "smsc.sign.sendSmsOrEmailMsg", isvParams, bizContent); + JSONObject response = JSON.parseObject(resStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + signInfo.setErrInfo(response.getString("code") + "[" + response.getString("note") + "]"); + log.error("【银盛进件】签约重发失败:code={}, msg={}", response.getString("code"), response.getString("note")); + result.setChannelVar1(JSON.toJSONString(signInfo)); + return result; + } + signInfo.setSignUrl(resData.getString("signUrl")); + signInfo.setState("签约中"); + signInfo.setOriginData(resData.toJSONString()); + + result.setChannelVar1(JSON.toJSONString(signInfo)); + return result; + + } catch (Exception e) { + log.info("签约重发异常", e); + throw new BizException("签约重发异常" + e.getMessage()); + } + } + + /** + * @date: 2022/7/21 10:23 + * @describe: 费率配置 + */ + @Override + public MchApplyment payRateConfig(JSONObject reqParamJSON, MchApplyment mchApplyment) { +// 云商服2.0接口不接入 + // 获取到 渠道商配置信息 +// ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); +// YspayIsvParams isvParams = (YspayIsvParams)configContextQueryService.queryIsvParams(mchApplyment); +// MchApplyment result = new MchApplyment(); +// try { +// List paywayFeeList = JSON.parseArray(reqParamJSON.getString("paywayFeeList"), PaywayFee.class); +// // 获取商户信息 +// if (StringUtils.isEmpty(mchApplyment.getSuccResParameter())) { +// result.setChannelVar1("商户信息不能为空"); +// result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); +// return result; +// } +// JSONObject mchParasmJson = JSONObject.parseObject(mchApplyment.getSuccResParameter()); +// if (mchParasmJson == null || StringUtils.isEmpty(mchParasmJson.getString("mercId"))) { +// result.setChannelVar1("商户信息不能为空"); +// result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); +// return result; +// } +// // 费率参数修改 +// YspayApplymentInfo applymentInfo = JSONObject.parseObject(mchApplyment.getApplyDetailInfo(), YspayApplymentInfo.class); +// applymentInfo.setPaywayFeeList(paywayFeeList); +// JSONObject infoJson = (JSONObject) JSONObject.toJSON(applymentInfo); +// result.setApplyDetailInfo(infoJson.toJSONString()); +// +// // 商户号 +// String mercId = mchParasmJson.getString("mercId"); +// JSONObject bizContent = new JSONObject(); +// // 商户号 +// bizContent.put("mercId", mercId); +// // 机构号 +// bizContent.put("accOrgNo", isvParams.getSrc()); +// +// JSONObject jsonObject = YspayApplymentInfo.convertPayConfig(paywayFeeList); +// // 交易权限 +// bizContent.put("scanServiceOpen", jsonObject.getString("scanServiceOpen")); +// // 费率信息 +// bizContent.put("easyFeeBean", jsonObject.getJSONObject("easyFeeBean")); +// log.info("[银盛费率配置] bizContent:{}", bizContent); +// // 发送请求 +// String resultStr = YspayKit.applymentRequest("/saas/orgScan/onlineTrading", "onlineTrading", isvParams, bizContent); +// JSONObject response = JSONObject.parseObject(resultStr); +// JSONObject resData = response.getJSONObject("data"); +// String code = resData.getString("code"); +// if ("00".equals(code)) { +// result.setState(MchApplyment.STATE_SUCCESS); +// result.setChannelVar1("【银盛费率配置】配置成功" + resData.toJSONString()); +// }else { +// result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); +// result.setChannelVar1("【银盛费率配置】配置失败" + resData.toJSONString()); +// log.error("请求失败:code={}, msg={}", code, resData.getString("note")); +// } +// +// // 开通D0到账 +// JSONObject bizContentOpen = new JSONObject(); +// // 商户号 +// bizContentOpen.put("mercId", mercId); +// // 1-开通 0-关闭 +// bizContentOpen.put("opType", "1"); +// // 垫资费率 +// bizContentOpen.put("feeRate", "0.02"); +// // 垫资最低金额(分) +// bizContentOpen.put("feeMin", "1"); +// log.info("[银盛开通D0到账] bizContentOpen:{}", bizContentOpen); +// String resultOpenStr = YspayKit.applymentRequest("/saas/orgScan/optOnlineD0", "optOnlineD0", isvParams, bizContentOpen); +// JSONObject responseOpen = JSONObject.parseObject(resultOpenStr); +// JSONObject resDataOpen = responseOpen.getJSONObject("data"); +// String codeOpen = resDataOpen.getString("code"); +// if ("00".equals(codeOpen)) { +// result.setState(MchApplyment.STATE_SUCCESS); +// result.setChannelVar1(result.getChannelVar1() + " 【银盛开通D0到账】配置成功" + resDataOpen.toJSONString()); +// }else { +// result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); +// result.setChannelVar1(result.getChannelVar1() + " 【银盛开通D0到账】配置失败"+ resDataOpen.toJSONString()); +// log.error("请求失败:code={}, msg={}", code, resDataOpen.getString("note")); +// } +// +// } catch (Exception e) { +// log.error("银盛进件[配置费率]失败:", e); +// throw new BizException(e.getMessage()); +// } + + return mchApplyment; + } + + @Override + public ChannelRetMsg configBindAppId(String configVal, String mchAppId, MchApplyment mchApplyment) { + JSONObject bizContent = new JSONObject(); + JSONObject params = JSON.parseObject(configVal); + String mchType = getWxMchType(params.getString("mchType")); + bizContent.put("mchType", mchType); + bizContent.put("appletAppid", params.getString("configWxBindLiteAppId")); + return commonReq(mchApplyment, mchAppId, bizContent); + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configVal, String mchAppId, MchApplyment mchApplyment) { + JSONObject bizContent = new JSONObject(); + JSONObject params = JSON.parseObject(configVal); + String mchType = getWxMchType(params.getString("mchType")); + bizContent.put("mchType", mchType); + bizContent.put("appid", params.getString("configWxBindAppId")); + return commonReq(mchApplyment, mchAppId, bizContent); + } + + @Override + public ChannelRetMsg configPayBaseUrl(String configVal, String mchAppId, MchApplyment mchApplyment) { + JSONObject bizContent = new JSONObject(); + JSONObject params = JSON.parseObject(configVal); + String mchType = getWxMchType(params.getString("mchType")); + bizContent.put("mchType", mchType); + bizContent.put("jsapiPath1", params.getString("configWxPayBaseUrl")); + return commonReq(mchApplyment, mchAppId, bizContent); + } + + private ChannelRetMsg commonReq(MchApplyment mchApplyment, String mchAppId, JSONObject bizContent) { + + // 获取到 渠道商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + YspayIsvsubMchParams isvsubMchParams = (YspayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchApplyment.getMchNo(), mchAppId, mchApplyment.getIfCode()); + + // 商户进件参数 + YspayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), YspayApplymentInfo.class); + + if (isvsubMchParams == null || StringUtils.isEmpty(isvsubMchParams.getMercId())) { + return ChannelRetMsg.confirmFail(null, "", "商户应用参数未配置,请先配置参数到应用"); + } + // 商户号 + bizContent.put("mercId", isvsubMchParams.getMercId()); + // 渠道编号 微信支付(网联) + bizContent.put("reportChannel", "NUCC_WECHAT"); + // 商户归属省 + bizContent.put("mercProv", applymentInfo.getMercProv()); + // 商户归属市 + bizContent.put("mercCity", applymentInfo.getMercCity()); + // 商户归属区 + bizContent.put("mercArea", applymentInfo.getMercArea()); + // 商户联系人姓名 + bizContent.put("contactsName", applymentInfo.getContactName()); + // 商户联系人手机 + bizContent.put("contactsTel", applymentInfo.getContactPhone()); + + // 发送请求 + String resultStr = YspayKit.wxQueryRequest("https://multiapi.ysepay.com:2443/busi-gate-api/mercScanReport", + "https://multiapi.ysepay.com", "ysepay.merchant.scan.report", isvParams, bizContent); + JSONObject response = JSON.parseObject(resultStr); + JSONObject resData = response.getJSONObject("ysepay_merchant_scan_report_response"); + String respCode = resData.getString("respCode"); + // 请求异常 + if (!"00".equals(respCode)) { + return ChannelRetMsg.confirmFail(null, respCode, resData.getString("respMsg")); + } + String apprSts = resData.getString("apprSts"); + // 业务异常 + if (!"00".equals(apprSts)) { + return ChannelRetMsg.confirmFail(null, apprSts, resData.getString("remark")); + } + + return ChannelRetMsg.confirmSuccess(null); + } + + private static String getWxMchType(String mchType) { + if (StringUtils.isNotEmpty(mchType)) { + String[] split = mchType.split("_"); + return split[1]; + } + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentResourceService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentResourceService.java new file mode 100644 index 0000000..d88b70e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayApplymentResourceService.java @@ -0,0 +1,93 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.io.resource.ClassPathResource; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IApplymentResourceService; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/*** +* 收付通银行编码数据 +* +* @author zx +* +* @date 2022/3/12 14:54 +*/ +@Service +@Slf4j +public class YspayApplymentResourceService implements IApplymentResourceService { + + @Override + public String getMcc() { + return null; + } + + @Override + public IPage getBankCode(IPage iPage, JSONObject queryParams) { + + String bankName = queryParams.getString("bankName"); + String settAccountType = queryParams.getString("settAccountType"); + + String resourcePath = "channel/sftpay/bankCodeCorporate.json"; // 对公 + if(MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(settAccountType)){ + resourcePath = "channel/sftpay/bankCodePersonal.json"; // 对私 + } + + ClassPathResource resource = new ClassPathResource(resourcePath); + + // 文件内容转为List + List records = JSONArray.parseArray(resource.readUtf8Str(), JSONObject.class); + + // 条件筛选 + if (StringUtils.isNotBlank(bankName)) { + records = records.stream().filter(jsonObject -> jsonObject.getString("bank_alias").contains(bankName)).collect(Collectors.toList()); + } + // 总条数 + iPage.setTotal(records.size()); + + // 分页截取records + iPage.setRecords(records.stream().skip(iPage.offset()).limit(iPage.getSize()).collect(Collectors.toList())); + + return iPage; + } + + @Override + public List getAreaCode(IsvParams isvParams, JSONObject reqParams) { + // 获取支付参数 + YspayIsvParams yspayIsvParams = (YspayIsvParams) isvParams; + + JSONObject bizContent = new JSONObject(); + bizContent.put("pageNumber", "1"); + bizContent.put("pageSize", "100"); + + if (reqParams == null) { + bizContent.put("parentCityCd", reqParams.getString("parentCode")); + }else { + bizContent.put("areaLevel", "1"); + } + + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/pregate/trade/findCmmtAreaInfoList", "pregate.trade.findCmmtAreaInfoList", yspayIsvParams, bizContent); + + String areaInfoStr = JSONObject.parseObject(resultStr).getJSONObject("data").getString("areaInfoList"); + + return JSONArray.parseArray(areaInfoStr, JSONObject.class); + } + + @Override + public String sendPubRequst(String type, String mchNo, String applyId, String jsonStr) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelNoticeService.java new file mode 100644 index 0000000..2050db8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelNoticeService.java @@ -0,0 +1,154 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.util.Map; + +/** + * 银盛支付 回调接口实现类 + * + * @author xiaoyu + * + * @date 2022/4/15 10:23 + */ +@Service +@Slf4j +public class YspayChannelNoticeService extends AbstractChannelNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + JSONObject reqParamJSON = getReqParamJSON(); + String payOrderId = reqParamJSON.getString("out_trade_no"); + return MutablePair.of(payOrderId, reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject respJson = (JSONObject) JSONObject.toJSON(params); + boolean verifyResult = verifyParams(respJson, mchAppConfigContext, payOrder); + // 验证参数失败 + if(!verifyResult){ + throw ResponseException.buildText("error"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("success"); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelBizData(respJson); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + result.setChannelOrderId(respJson.getString("trade_no")); + //如果是支付宝 则需要去除前两位 + result.setPlatformOrderNo(respJson.getString("channel_recv_sn")); + //银盛订单号特殊处理 + if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(payOrder.getWayCodeType())){ + result.setPlatformOrderNo(result.getPlatformOrderNo().substring(2)); + } + YsCardType val = YsCardType.getVal(respJson.getString("card_type")); + if(val == null){ + result.setDrType(CS.DrType.OTHER.getType()); + }else{ + switch (val){ + case CREDIT: + result.setDrType(CS.DrType.CREDIT.getType()); + break; + case DEBIT: + result.setDrType(CS.DrType.DEBIT.getType()); + break; + } + } + result.setPlatformMchOrderNo(respJson.getString("channel_send_sn")); + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证银盛支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, PayOrder payOrder) { + try { + String logPrefix = "【处理[银盛]支付回调】"; + + log.info("{} 回调参数: jsonParams:{}", logPrefix, jsonParams); + String sign = jsonParams.getString("sign"); + String tradeStatus = jsonParams.getString("trade_status"); + Map paramsMap = jsonParams.toJavaObject(Map.class); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空:sign:{}", sign); + return false; + } + + if (!YspayKit.TRADE_SUCCESS.equals(tradeStatus)) { + log.info("订单状态未支付成功:tradeStatus:{}", tradeStatus); + return false; + } + + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), payOrder.getIfCode()); + + // 证书地址 + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + boolean verifyResult = false; + if ("RSA".equals(isvParams.getSignType())) { + FileInputStream fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile())); + verifyResult = SignRsaUtil.asynVerifyYsRsa(fileInputStream, paramsMap); + }else if ("SM".equals(isvParams.getSignType())){ + verifyResult = SignSmUtil.asynVerifyYsSm(certFilePath, paramsMap); + }else { + log.error("未识别的签名类型"); + } + + //验签失败 + if(!verifyResult) { + log.info("{} 验签失败! 回调参数:parameter = {}, certFilePath={} ", logPrefix, jsonParams, certFilePath); + return false; + } + return true; + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelOrderAcceptService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelOrderAcceptService.java new file mode 100644 index 0000000..e5f15d5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelOrderAcceptService.java @@ -0,0 +1,267 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.crypto.SecureUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.aliyun.oss.ServiceException; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.ResponseException; +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 com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelOrderAcceptService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.AESUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * 智能POS回调 + * + * @author zx + * + * @date 2021-06-07 07:15 + */ +@Service +@Slf4j +public class YspayChannelOrderAcceptService extends AbstractChannelOrderAcceptService { + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + public JSONObject getReturnJson() { + JSONObject returnJson = new JSONObject(); + returnJson.put("code", "00"); + returnJson.put("msg", "成功"); + return returnJson; + } + + @Override + public ChannelOrderAcceptParams parseParams(HttpServletRequest request, IsvParams isvParams) { + + try { + + String bodyStr = getBody(request); + YspayIsvParams yspayIsvParams = (YspayIsvParams) isvParams; + String posPrivateKey = yspayIsvParams.getPosPrivateKey(); + String strAes = AESUtil.decryptStrAES(bodyStr, posPrivateKey); + JSONObject params = JSON.parseObject(strAes); + + log.info("银盛智能POS【订单通知模式】通知参数, 通知参数:{}, 解密参数:{}", bodyStr, strAes); + + String deviceNo = params.getString("t41TrmNo"); + String payStatus = params.getString("transType"); + + String tradeType = ""; // 交易状态:1.支付成功,2退款成功,3撤销成功,4冲正成功 + if (POS_TRANS_TYPE_PAY_MAP.get(payStatus) != null && POS_TRANS_TYPE_PAY_MAP.get(payStatus)) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_PAYMENT; + }else if (POS_TRANS_TYPE_REFUND_MAP.get(payStatus) != null && POS_TRANS_TYPE_REFUND_MAP.get(payStatus)) { + tradeType = ChannelOrderAcceptParams.TRADE_TYPE_REFUND; + } + + return ChannelOrderAcceptParams.buildAutoPosParams(tradeType, deviceNo, params); + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("FAIL"); + } + } + + @Override + public ChannelOrderAcceptRetMsg payNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) { + try { + String logPrefix = "银盛智能POS【订单通知模式】 支付通知"; + + ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg(); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + +// // 签名参数 +// String checkValue = jsonParams.getString("checkValue"); +// +// // 验签 +// boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, ifCode, checkValue, logPrefix); +// if(!verifyResult){ +// log.info("{}验证通知数据及签名失败", logPrefix); +// throw ResponseException.buildText("FAIL"); +// } + + // 支付状态 + String status = jsonParams.getString("txnSts"); + // 支付成功 + if (YspayKit.POS_CODE_S.equals(status)) { + result.setResponseEntity(jsonResp(getReturnJson())); // 通知上游处理成功 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + // 交易类型:01-银联云闪付 02-微信 03-支付宝 + String payType = jsonParams.getString("payType"); + + // 扫码支付参考号,扫码交易时存在且唯一 + String channelOrderId = jsonParams.getString("logNo"); + + result.setChannelOrderId(channelOrderId); // 渠道订单号,必填 +// result.setChannelUserId(reqData.getString("buyer_id")); + + result.setChannelAmount(jsonParams.getLong("t4TxnAmt")); // 订单金额,单位分,必填 + result.setChannelWayCode(CS.PAY_WAY_CODE.AUTO_POS); // 支付方式,必填 + result.setChannelWayCodeType(covertWayCodeType(payType)); // 支付方式类型,必填 + result.setBizOrderId(StringUtils.isNotBlank(jsonParams.getString("logNo")) ? jsonParams.getString("logNo").trim() : ""); + } + return result; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("FAIL"); + } + } + + @Override + public ChannelOrderAcceptRetMsg refundNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) { + try { + String logPrefix = "银盛智能POS【订单通知模式】 退款通知"; + + ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg(); + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + log.info("{} 通知参数, jsonParams:{}", logPrefix, jsonParams); + +// // 签名参数 +// String checkValue = jsonParams.getString("checkValue"); +// +// // 验签 +// boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, ifCode, checkValue, logPrefix); +// if(!verifyResult){ +// log.info("{}验证通知数据及签名失败", logPrefix); +// throw ResponseException.buildText("FAIL"); +// } + + // 退款状态 + String status = jsonParams.getString("txnSts"); + // 退款成功 + if (YspayKit.POS_CODE_S.equals(status)) { + result.setResponseEntity(jsonResp(getReturnJson())); // 通知上游处理成功 + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + result.setChannelOrderId(jsonParams.getString("ologNo")); // 渠道退款订单号,必填 + + // 交易类型:01-银联云闪付 02-微信 03-支付宝 + String payType = jsonParams.getString("payType"); + + // 扫码支付参考号,扫码交易时存在且唯一 + String channelOrderId = jsonParams.getString("ologNo"); + + result.setChannelAmount(jsonParams.getLong("t4TxnAmt")); // 退款金额,单位分,必填 + result.setChannelPayOrderId(channelOrderId); // 原渠道订单号(和支付订单渠道订单号一致),退款必填 + result.setBizOrderId(StringUtils.isNotBlank(jsonParams.getString("ologNo")) ? jsonParams.getString("ologNo").trim() : ""); + } + return result; + + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("FAIL"); + } + } + + private String covertWayCodeType(String payType) { + switch (payType){ + case "01": return CS.PAY_WAY_CODE_TYPE.UNIONPAY; + case "02": return CS.PAY_WAY_CODE_TYPE.WECHAT; + case "03": return CS.PAY_WAY_CODE_TYPE.ALIPAY; + default: return CS.PAY_WAY_CODE_TYPE.OTHER; + } + } + + /** + * 验签 + * @return + */ + public boolean validateSign(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, String ifCode, String reqSign, String logPrefix) { + + // 交易数据 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + + // 商户号 + String signStr = jsonParams.getString("t42MercId") + + // 终端号 + jsonParams.getString("t41TrmNo") + + // 订单号 + jsonParams.getString("logNo") + + // 日期 + jsonParams.getString("acDt") + + // 私钥 + isvParams.getPosPrivateKey(); + + log.info("{}待验签字符串:{}, ", logPrefix, signStr); + String md5Result = SecureUtil.md5(signStr); + + return StringUtils.equalsIgnoreCase(reqSign, md5Result); + } + + /** + * 获取请求数据 + * + * @param request + * @return + */ + protected final String getBody(HttpServletRequest request) { + try { + @Cleanup InputStreamReader in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8); + StringBuilder bf = new StringBuilder(); + int len; + char[] chs = new char[1024]; + while ((len = in.read(chs)) != -1) { + bf.append(new String(chs, 0, len)); + } + return bf.toString(); + } catch (Exception e) { + log.error("请求头部取数据异常:{}", e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + public static final Map POS_TRANS_TYPE_PAY_MAP = new HashMap<>(); + static { + POS_TRANS_TYPE_PAY_MAP.put("2010020", true); // 消费 + POS_TRANS_TYPE_PAY_MAP.put("2010010", true); // 消费冲正 + POS_TRANS_TYPE_PAY_MAP.put("1300001", true); // 聚合扫码支付 + POS_TRANS_TYPE_PAY_MAP.put("2080001", true); // 微信反扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2080010", true); // 微信正扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2070001", true); // 支付宝反扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2070008", true); // 支付宝终端正扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2050001", true); // 银联反扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2050008", true); // 银联正扫支付 + POS_TRANS_TYPE_PAY_MAP.put("2090028", true); // 订单支付 + POS_TRANS_TYPE_PAY_MAP.put("2020001", true); // 扫码快付支付 + POS_TRANS_TYPE_PAY_MAP.put("2050009", true); // 银联固定二维码支付 + POS_TRANS_TYPE_PAY_MAP.put("2080006", true); // 微信公众号支付 + POS_TRANS_TYPE_PAY_MAP.put("2070009", true); // 支付宝公众号支付 + + /** 预授权完成请求和完成通知 是支付成功的 **/ + } + public static final Map POS_TRANS_TYPE_REFUND_MAP = new HashMap<>(); + static { + POS_TRANS_TYPE_REFUND_MAP.put("2010080", true); // 退货 + POS_TRANS_TYPE_REFUND_MAP.put("2010030", true); // 消费撤销 + POS_TRANS_TYPE_REFUND_MAP.put("1300004", true); // 聚合扫码退款 + POS_TRANS_TYPE_REFUND_MAP.put("2080004", true); // 微信支付退款 + POS_TRANS_TYPE_REFUND_MAP.put("2070004", true); // 支付宝退款 + POS_TRANS_TYPE_REFUND_MAP.put("2050004", true); // 银联二维码退款 + POS_TRANS_TYPE_REFUND_MAP.put("2090032", true); // 订单支付撤销 + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelRefundNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelRefundNoticeService.java new file mode 100644 index 0000000..fca4cfe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelRefundNoticeService.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelRefundNoticeService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.util.Map; + +/** + * 银盛退款回调接口实现类 + * + * @author xiaoyu + * + * @date 2021/12/24 11:31 + */ +@Service +@Slf4j +public class YspayChannelRefundNoticeService extends AbstractChannelRefundNoticeService { + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + try { + JSONObject reqParamJSON = getReqParamJSON(); + String payOrderId = reqParamJSON.getString("out_trade_no"); + return MutablePair.of(payOrderId, reqParamJSON); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + log.info("【银盛】退款回调参数:{} ", jsonParams); + // 校验支付回调 + boolean verifyResult = verifyParams(jsonParams, mchAppConfigContext); + // 验证参数失败 + if(!verifyResult) { + log.info("【银盛】验证参数失败, orderId:{}", refundOrder.getRefundOrderId()); + throw ResponseException.buildText("ERROR"); + } + ResponseEntity okResponse = textResp("success"); + ChannelRetMsg result = new ChannelRetMsg(); + result.setResponseEntity(okResponse); + result.setChannelOrderId(jsonParams.getString("trade_no")); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + String trade_status = jsonParams.getString("trade_status"); + if(YspayKit.TRADE_PROCESS.equals(trade_status)){ + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if(YspayKit.TRADE_SUCCESS.equals(trade_status) || YspayKit.TRADE_PART_REFUND.equals(trade_status) || YspayKit.TRADE_ALL_REFUND.equals(trade_status)){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + /** + * 验证银盛退款通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + log.info("【银盛】退款回调参数: jsonParams:{}", jsonParams); + String sign = jsonParams.getString("sign"); + Map paramsMap = jsonParams.toJavaObject(Map.class); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空:sign:{}", sign); + return false; + } + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + // 证书地址 + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + boolean verifyResult = false; + if ("RSA".equals(isvParams.getSignType())) { + FileInputStream fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile())); + verifyResult = SignRsaUtil.asynVerifyYsRsa(fileInputStream, paramsMap); + }else if ("SM".equals(isvParams.getSignType())){ + verifyResult = SignSmUtil.asynVerifyYsSm(certFilePath, paramsMap); + }else { + log.error("未识别的签名类型"); + } + //验签失败 + if(!verifyResult) { + log.info("【银盛】退款回调验签失败! 回调参数:parameter = {} ", jsonParams); + return false; + } + return true; + }catch (Exception e) { + return false; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelUserService.java new file mode 100644 index 0000000..01e1907 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayChannelUserService.java @@ -0,0 +1,76 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** +* 银盛 获取银联userId实现类 +* +* @author jmdhapy +* +* @date 2022/3/17 16:51 +*/ +@Service +@Slf4j +public class YspayChannelUserService implements IChannelUserService { + + @Autowired protected ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + //云闪付返回地址 + String ysfRedirectUrl = String.format("https://qr.95516.com/qrcGtwWeb-web/api/userAuth?version=1.0.0&redirectUrl=%s", callbackUrlEncode); + log.info("银盛ysRedirectUrl={}", ysfRedirectUrl); + return ChannelUserInfoMsg.gen(ysfRedirectUrl, null); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String logPrefix = "【银盛获取银联行业码用户ID】"; + try { + String userAuthCode = reqParams.getString("userAuthCode"); //云闪付 userAuthCode + String appUpIdentifier = reqParams.getString("appUpIdentifier"); + log.info("{} userAuthCode={}, appUpIdentifier={}", logPrefix, userAuthCode, appUpIdentifier); + JSONObject bizContent = new JSONObject(); + + // 用户授权码 + bizContent.put("userAuthCode", userAuthCode); + // 银联支付标识 + bizContent.put("appUpIdentifier", appUpIdentifier); + + String result = YspayKit.payRequest("ysepay.online.cupgetmulapp.userid", mchAppConfigContext, bizContent, null, ifCode); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_cupgetmulapp_userid_response"); + String code = response.getString("code"); + String userId = ""; + if (YspayKit.RES_CODE.equals(code)) { + String tradeStatus = response.getString("trade_status"); + if ("SUCCESS".equals(tradeStatus)) { + userId = response.getString("userId"); + } + }else { + log.error("请求失败:code={}, sub_msg={}", code, response.getString("sub_msg")); + return userId; + } + return userId; + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionRecordChannelNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionRecordChannelNotifyService.java new file mode 100644 index 0000000..92aab42 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionRecordChannelNotifyService.java @@ -0,0 +1,135 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.DivisionChannelNotifyModel; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionRecordChannelNotifyService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignRsaUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.SignSmUtil; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO + * + * @author crystal + * @date 2024/1/28 14:56 + */ +@Service +@Slf4j +public class YspayDivisionRecordChannelNotifyService extends AbstractDivisionRecordChannelNotifyService { + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request) { + JSONObject reqParamJSON = getReqParamJSON(); + log.info("【银盛分账】异步通知参数:{}", reqParamJSON); + return MutablePair.of(reqParamJSON.getString("out_trade_no"), reqParamJSON); + } + + @Override + public DivisionChannelNotifyModel doNotify(HttpServletRequest request, Object params, List recordList, MchAppConfigContext mchAppConfigContext) { + JSONObject notifyData = (JSONObject) params; + boolean verifyResult = verifyParams(notifyData, mchAppConfigContext); + if(!verifyResult){ + log.info("银盛分账回调签名校验失败"); + throw ResponseException.buildText("error"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("success"); + DivisionChannelNotifyModel result = new DivisionChannelNotifyModel(); + String division_status_code = notifyData.getString("division_status_code"); + //分账处理中 + ChannelRetMsg.ChannelState channelState; + if("00".equals(division_status_code) || "02".equals(division_status_code) || "03".equals(division_status_code)){ + channelState = ChannelRetMsg.ChannelState.CONFIRM_SUCCESS; + }else if("01".equals(division_status_code)){ + channelState = ChannelRetMsg.ChannelState.WAITING; + }else if("99".equals(division_status_code)){ + channelState = ChannelRetMsg.ChannelState.CONFIRM_FAIL; + }else{ + channelState = ChannelRetMsg.ChannelState.UNKNOWN; + } + String note = notifyData.getString("note"); + Map recordResultMap = new HashMap<>(); + for (PayOrderDivisionRecord pdr:recordList) { + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(channelState); + channelRetMsg.setChannelErrMsg(note); + channelRetMsg.setChannelOriginResponse(notifyData.getString("detailResults")); + recordResultMap.put(pdr.getRecordId(),channelRetMsg); + } + result.setRecordResultMap(recordResultMap); + result.setApiRes(okResponse); + return result; + } + + /** + * 校验签名 + * @param notifyData + * @param mchAppConfigContext + * @return + */ + /** + * 验证银盛支付通知参数 + * @return + */ + public boolean verifyParams(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext) { + try { + String logPrefix = "【处理[银盛]分账回调】"; + log.info("{} 回调参数: jsonParams:{}", logPrefix, jsonParams); + String sign = jsonParams.getString("sign"); + Map paramsMap = jsonParams.toJavaObject(Map.class); + if (StringUtils.isEmpty(sign)) { + log.info("验签参数为空:sign:{}", sign); + return false; + } + // 校验支付回调 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + // 证书地址 + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + boolean verifyResult = false; + if ("RSA".equals(isvParams.getSignType())) { + FileInputStream fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile())); + verifyResult = SignRsaUtil.asynVerifyYsRsa(fileInputStream, paramsMap); + }else if ("SM".equals(isvParams.getSignType())){ + verifyResult = SignSmUtil.asynVerifyYsSm(certFilePath, paramsMap); + }else { + log.error("未识别的签名类型"); + } + //验签失败 + if(!verifyResult) { + log.info("{} 验签失败! 回调参数:parameter = {}, certFilePath={} ", logPrefix, jsonParams, certFilePath); + return false; + } + return true; + }catch (Exception e) { + log.error("验证签名异常", e); + return false; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionService.java new file mode 100644 index 0000000..c43c054 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayDivisionService.java @@ -0,0 +1,251 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +/** + * 分账接口 + * + * @author xiaoyu + * + * @date 2023/8/9 8:45 + */ +@Slf4j +@Service +public class YspayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "[银盛添加分账]"; + try { + // 新创建的分账接收者的mchId + // 当channelExtInfo 传入: {} , 说明是subMchId直接绑定模式 + String newDivisionReceiverSubMchId = mchDivisionReceiver.getAccNo(); + + log.info("{}, 接收人账号{}", logPrefix, newDivisionReceiverSubMchId); + //在channelAttach数据中,写入 渠道用户编号 + return ChannelRetMsg.confirmSuccess(null).setChannelAttach(newDivisionReceiverSubMchId); + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + + try { + JSONObject bizContent = new JSONObject(); + // 商户批次号,格式:(S|F)+15位唯一流水,建议格式:S+YYYYMMDD+XXXXXXX.F表示代付,S表示代收。单笔交易可空,批量交易时必写 + // 0-16位 +// bizContent.put("out_batch_no", batchOrderId); + // 订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 收款商户号 + bizContent.put("payee_usercode", payOrder.getChannelMchNo()); + // 原交易订单金额 20长度位,保留2位小数 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt()+"")); + // 原订单是否参与分账 01:是,02否 + bizContent.put("is_divistion", "01"); + // 是否重新分账 Y:是,N:否 + bizContent.put("is_again_division", "Y"); + // 分行模式 01 :比例,02:金额 + bizContent.put("division_mode", "02"); + + JSONArray receivers = new JSONArray(); + BigDecimal totalDivAmt = BigDecimal.ZERO; + boolean isCheckFee = false; + for (int i = 0; i < recordList.size(); i++) { + PayOrderDivisionRecord record = recordList.get(i); + if(record.getCalDivisionAmount() <= 0){ //金额为 0 不参与分账处理 + continue; + } + if(StringUtils.isEmpty(record.getChannelAccNo())){ // 判断是否都包含渠道号码 + throw new BizException(record.getAccName() + "账号没有分账渠道号, 本次分账失败"); + } + + JSONObject receiver = new JSONObject(); + receiver.put("division_mer_usercode", record.getChannelAccNo()); + totalDivAmt = totalDivAmt.add(BigDecimal.valueOf(record.getCalDivisionAmount())); + receiver.put("div_amount", AmountUtil.convertCent2Dollar(record.getCalDivisionAmount())); + // 由商户收取手续费 是否收取手续费(01:是,02否) + if (record.getAccType() == 1) { + isCheckFee = true; + receiver.put("is_chargeFee", "01"); + }else { + receiver.put("is_chargeFee", "02"); + } + receivers.add(receiver); + } + //银盛加收款方的处理 + BigDecimal paymentDivAmt = (BigDecimal.valueOf(payOrder.getFindAmt()).subtract(totalDivAmt)).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_EVEN); + if(paymentDivAmt.compareTo(BigDecimal.ZERO) > 0){ + JSONObject receiver = new JSONObject(); + receiver.put("division_mer_usercode", payOrder.getChannelMchNo()); + receiver.put("div_amount",paymentDivAmt.toPlainString()); + receiver.put("is_chargeFee",isCheckFee ? "02" : "01"); + receivers.add(receiver); + } + if(receivers.isEmpty()){ + return ChannelRetMsg.confirmSuccess(null); + } + // 分账对象 + bizContent.put("div_list", receivers); + // 发起分账请求 + String result = YspayKit.divisionRequest(YspayKit.DIVISION_URL, "ysepay.single.division.online.accept", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_single_division_online_accept_response"); + String code = response.getString("code"); + log.info("【银盛分账】订单号:{},分账返回结果:{}", payOrder.getPayOrderId(),response); + if (YspayKit.RES_CODE.equals(code)) { + String returnCode = response.getString("returnCode"); + // 分账受理中 + if("0000".equals(returnCode)){ + ChannelRetMsg waiting = ChannelRetMsg.waiting(); + waiting.setChannelErrMsg(response.getString("retrunInfo")); + return waiting; + } + } + // 失败 + return ChannelRetMsg.confirmFail().setChannelErrCode(response.getString("code")).setChannelErrMsg(JSON.toJSONString(response)); + + } catch (ChannelException e) { + + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + + } catch (Exception e) { + log.error("银盛分账异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "【银盛分账回退】"; + + try { + YspayIsvsubMchParams mchParams = (YspayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrderDivisionRecord.getIfCode()); + JSONObject bizContent = new JSONObject(); + + // 商户原交易订单号 + bizContent.put("out_trade_no", payOrderDivisionRecord.getPayOrderId()); + // 商户系统的交易发生日期格式yyyyMMdd 示例值:20180525 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 银盛原交易流水号 + bizContent.put("trade_no", payOrder.getChannelOrderNo()); + // 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数,Number(10,2)指10位长度,2位精度 + bizContent.put("refund_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount()+"")); + // 退款的原因说明,该参数最长为50个汉字。 + bizContent.put("refund_reason", "分账退款"); + // 标商户系统生成的退款订单号,标识一次退款请求,同一笔交易多次退款需要保证唯一。 + bizContent.put("out_request_no", payOrderDivisionRefundRecord.getDivisionRefundId()); + // 原交易是否参与分账(01或空代表是,02代表否) + bizContent.put("is_division", "01"); + // 原交易分账模式(01:比例,02:金额) + bizContent.put("ori_division_mode", "02"); + + JSONArray refundSplitInfo = new JSONArray(); + JSONObject refundJson = new JSONObject(); + refundJson.put("refund_mer_id", payOrderDivisionRecord.getChannelAccNo()); + refundJson.put("refund_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount())); + refundJson.put("ori_division_mode", "02"); + refundSplitInfo.add(refundJson); + + JSONArray orderDivList = new JSONArray(); + JSONObject orderDivJson = new JSONObject(); + orderDivJson.put("division_mer_id", payOrderDivisionRecord.getChannelAccNo()); + orderDivJson.put("division_amount", AmountUtil.convertCent2Dollar(payOrderDivisionRefundRecord.getDivisionRefundAmount())); + orderDivJson.put("is_charge_fee", "02"); + orderDivList.add(orderDivJson); + + bizContent.put("refund_split_info", refundSplitInfo); + bizContent.put("order_div_list", orderDivList); + + String result = YspayKit.divisionRequest(YspayKit.DIVISION_REFUND_URL, "ysepay.online.trade.refund.split", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, null, payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_trade_refund_split_response"); + String code = response.getString("code"); + if (YspayKit.RES_CODE.equals(code)) { + return ChannelRetMsg.confirmSuccess(response.getString("trade_no")); + }else { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(code); + channelRetMsg.setChannelErrMsg(response.getString("msg")); + return channelRetMsg; + } + + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "【银盛分账余额查询】"; + try { + Long balanceAmt = 0L; + return balanceAmt; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "银盛分账账号提现"; + try { + return ChannelRetMsg.waiting(); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayGetApplymentDataService.java new file mode 100644 index 0000000..cd53fbe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayGetApplymentDataService.java @@ -0,0 +1,77 @@ + +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.exception.YsConfigException; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.LinkedList; +import java.util.List; + +/*** +* +* @author zx +* +* @date 2022/1/4 14:54 +*/ +@Service +@Slf4j +public class YspayGetApplymentDataService implements IGetApplymentDataService { + + @Override + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams)configContextQueryService.queryIsvParams(isvNo, CS.IF_CODE.YSPAY); + List bankBranchList = new LinkedList<>(); + try { + + JSONObject bizContent = new JSONObject(); + //地区编码 自动查询下级区域 包括市、地区 1、支行行号不能与地区编码、行别同时为空;2、行别不为空时,地区编码必填 + bizContent.put("cityCode", cityCode); + //银行名称 模糊匹配 + bizContent.put("openBankName", bankName); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/pregate/trade/findBankNameAndBankCode", "pregate.trade.findBankNameAndBankCode", isvParams, bizContent); + JSONObject bankJson = JSON.parseObject(resultStr); + + if (bankJson == null) { + return bankBranchList; + } + JSONObject dataJson = bankJson.getJSONObject("data"); + if (dataJson == null) { + return bankBranchList; + } + JSONArray bankCodeList = dataJson.getJSONArray("bankCodeList"); + bankCodeList.forEach(item -> { + JSONObject itemJson = JSON.parseObject(item.toString()); + JSONObject bankBranch = new JSONObject(); + bankBranch.put("bankType", itemJson.getString("bankType")); + bankBranch.put("branchName", itemJson.getString("bankName")); + bankBranch.put("branchNo", itemJson.getString("bankCode")); + bankBranchList.add(bankBranch); + }); + + } catch (YsConfigException e) { + log.error("获取银行信息列表异常:" + e.getMessage()); + throw new BizException("通道配置参数异常,请联系平台运营处理"); + } catch (Exception e) { + log.error("获取银行信息列表异常:" + e.getMessage()); + throw e; + } + return bankBranchList; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchAlipayConfigService.java new file mode 100644 index 0000000..f868d28 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchAlipayConfigService.java @@ -0,0 +1,115 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class YspayIsvmchAlipayConfigService implements IIsvmchAlipayConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ApplymentSignInfo alipayOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + // 支付宝渠道拓展地址 + result.setSignUrl(isvParams.getAliChannelExtUrl()); + // 图片类型 + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + if (suJson == null || StringUtils.isEmpty(suJson.getString("mercId"))) { + result.setErrInfo("银盛商户号为空"); + return result; + } + // 银盛商户号 + String mercId = suJson.getString("mercId"); + + LambdaQueryChainWrapper zfbSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + MchSubInfoEntity zfb = zfbSubInfoQuery.one(); + + if (zfb == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + zfb = zfbSubInfoQuery.one(); + } + + if (zfb == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if (StrUtil.isEmpty(zfb.getSubMchId())) { + result.setState("未报备"); + result.setErrInfo("[" + zfb.getRemark() + "]"); + return result; + } else { + result.setChannelSubMchId(zfb.getSubMchId()); + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("mercId", mercId); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/pregate/alipay/getAuthState", "pregate.alipay.getAuthState", isvParams, bizContent); + JSONObject response = JSON.parseObject(resultStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState("04"); + result.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + return result; + } + + String authState = resData.getString("authState"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "ZFB"); + if ("1".equals(authState)) { + result.setState("已授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } else if ("2".equals(authState)) { + result.setState("已销户"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_LOGOFF).update(); + } else { + result.setState("未授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..b22667c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchApplymentNotifyService.java @@ -0,0 +1,294 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.ApplymentNotify; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.concurrent.ExecutorService; + +@Slf4j +@Service +public class YspayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private YspayApplymentApiService yspayApplymentApiService; + + @Autowired + private YspayMchApplymentService yspayMchApplymentService; + + @Autowired + private ExecutorService executorService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Autowired + private MchModifyApplymentService mchModifyApplymentService; + + @Override + public ResponseEntity retOk(Object params) { + return ResponseEntity.ok("success"); + } + + /** + * 银盛入网和签约的回调链接组装参数中,包含了商户号,urlApplyId即商户的applyId + */ + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + try { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + String bizContent = reqParamJSON.getString("bizContent"); + // 使用TypeReference,防止 ApplymentNotify.Report.thirdMercList的ThirdMerc的类型被擦除 + ApplymentNotify applymentNotify = JSON.parseObject(bizContent, ApplymentNotify.class); + + if (ApplymentNotify.TYPE_MCH_APPLY.equals(applymentNotify.getNotifyType()) + || ApplymentNotify.TYPE_MCH_SIGN.equals(applymentNotify.getNotifyType()) + || ApplymentNotify.TYPE_MCH_REPORT.equals(applymentNotify.getNotifyType()) + || ApplymentNotify.TYPE_MCH_CHANGE.equals(applymentNotify.getNotifyType())) { + // 这些回调接口参数都由接口参数配置,故将商户号带入其中 + return MutablePair.of(urlApplyId, applymentNotify); + } + + return null; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + + ApplymentNotify applymentNotify = (ApplymentNotify) params; + + MutablePair result = null; + switch (applymentNotify.getNotifyType()) { + case ApplymentNotify.TYPE_MCH_APPLY: + result = handleAuditApply(applymentNotify, mchApplyment); + break; + case ApplymentNotify.TYPE_MCH_CHANGE: + handleModifyApply(applymentNotify, mchApplyment); + result = MutablePair.of(null, retOk(null)); + break; + case ApplymentNotify.TYPE_MCH_SIGN: + // 签约回调 + result = handleSignApply(applymentNotify, mchApplyment); + break; + case ApplymentNotify.TYPE_MCH_REPORT: + // 报备异步通知 + if ("00".equals(applymentNotify.getStatus())) { + // 报备异步处理 + executorService.execute(() -> yspayMchApplymentService.subMchColl(mchApplyment, applymentNotify.getReport())); + } + + // 报备回调返回空 + return MutablePair.of(null, retOk(null)); + default: + result = MutablePair.of(null, retOk(null)); + } + + return result; + } + + private MutablePair handleSignApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + MchApplyment updateRecordAudit = new MchApplyment(); + + if ("00".equals(applymentNotify.getStatus())) { + // 签约成功,完成进件 + updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS); + updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getAuth().getNote() + "]"); + updateRecordAudit.setApplyId(mchApplyment.getApplyId()); + JSONObject sucJSON = JSON.parseObject(mchApplyment.getSuccResParameter()); + if (sucJSON == null) { + sucJSON = new JSONObject(); + } + sucJSON.put("mercId", applymentNotify.getAuth().getMercId()); + updateRecordAudit.setSuccResParameter(sucJSON.toJSONString()); + updateRecordAudit.setChannelMchNo(applymentNotify.getAuth().getMercId()); + + // TODO 银盛入网签约完成 业务大厅添加变更数据将T1变为D1并待审核 + if ("yspay".equals(mchApplyment.getIfCode())){ + MchModifyApplymentEntity modifyApplyment=new MchModifyApplymentEntity(); + modifyApplyment.setModifyApplyId(SeqKit.genMchNotifyApplyNo()); + modifyApplyment.setApplyId(mchApplyment.getApplyId()); + // modifyApplyment.setChannelApplyNo(mchApplyment.getChannelApplyNo()); + modifyApplyment.setChannelMchNo(mchApplyment.getChannelMchNo()); + modifyApplyment.setMchNo(mchApplyment.getMchNo()); + modifyApplyment.setIfCode(mchApplyment.getIfCode()); + modifyApplyment.setIfName(mchApplyment.getIfName()); + //商户本次变更前数据 + MchApplyment applyment = mchApplymentService.getById(mchApplyment.getApplyId()); + String jsonString = JSONObject.toJSONString(applyment); + modifyApplyment.setOriginDetailInfo(jsonString); + //商户本次变更信息 + modifyApplyment.setApplyDetailInfo("{\"settlementType\":\"D1\"}"); + modifyApplyment.setApplyPageType(applyment.getApplyPageType()); + //变更类型为6 结算类型变更 + modifyApplyment.setModifyApplyType((byte) 6); + //状态默认为审核中 + modifyApplyment.setState((byte) 1); + modifyApplyment.setCreatedAt(new Date()); + mchModifyApplymentService.save(modifyApplyment); + } + return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null)); + } + + if ("90".equals(applymentNotify.getStatus()) || "99".equals(applymentNotify.getStatus())) { + // 驳回 + updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getAuth().getNote() + "]"); + updateRecordAudit.setApplyId(mchApplyment.getApplyId()); + + return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null)); + } + + return MutablePair.of(null, retOk(null)); + } + + private MutablePair handleAuditApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + JSONObject jsonObject = JSON.parseObject(mchApplyment.getApplyDetailInfo()); + + String channelVar1 = mchApplyment.getChannelVar1(); + JSONObject channelVarJson; + try { + channelVarJson = JSON.parseObject(channelVar1); + } catch (Exception e) { + channelVarJson = new JSONObject(); + } + + channelVarJson.putAll(((JSONObject) JSON.toJSON(applymentNotify.getCust()))); + mchApplyment.setChannelVar1(channelVarJson.toJSONString()); + + if ("00".equals(applymentNotify.getStatus())) { + com.jeequan.jeepay.core.entity.MchApplyment signApplyResult = yspayApplymentApiService.signApply(jsonObject, mchApplyment); + signApplyResult.setChannelVar1(mchApplyment.getChannelVar1()); + return MutablePair.of(signApplyResult, retOk(null)); + } + + if ("90".equals(applymentNotify.getStatus()) || "99".equals(applymentNotify.getStatus())) { + MchApplyment updateRecordAudit = new MchApplyment(); + // 驳回 + updateRecordAudit.setApplyId(mchApplyment.getApplyId()); + updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getCust().getNote() + "]"); + updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null)); + } + + if ("10".equals(applymentNotify.getStatus())) { + MchApplyment updateRecordAudit = new MchApplyment(); + updateRecordAudit.setApplyId(mchApplyment.getApplyId()); + updateRecordAudit.setApplyErrorInfo("[" + applymentNotify.getCust().getNote() + "]"); + updateRecordAudit.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_UPSTREAM_MANUAL_REVIEW); + return MutablePair.of(mchInfoConverter.toModel(updateRecordAudit), retOk(null)); + } + + return MutablePair.of(null, retOk(null)); + } + + private void handleModifyApply(ApplymentNotify applymentNotify, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + ApplymentNotify.Change change = applymentNotify.getChange(); + String changeSysFlowId = change.getChangeSysFlowId(); + + MchModifyApplyment modifyApplyment = getModifyApplymentByChannelApplyNo(changeSysFlowId); + + IIsvmchModifyApplymentService isvmchModifyApplymentService = IsvFactory.getIsvMchModifyApplymentService(CS.IF_CODE.YSPAY); + + if (mchApplyment.getState() == MchApplyment.STATE_SUCCESS) { + // 已经变更完成,直接退出 + return; + } + + switch (change.getStatus()) { + case "00": // 变更成功 + handleSuccessfulChange(modifyApplyment, mchApplyment, isvmchModifyApplymentService); + break; + case "03": // 待签约 + handleWaitingForSign(modifyApplyment, mchApplyment, isvmchModifyApplymentService); + break; + default: // 其他状态统一定为驳回 + handleRejectedState(modifyApplyment, change.getNote()); + break; + } + } + + private MchModifyApplyment getModifyApplymentByChannelApplyNo(String channelApplyNo) { + LambdaQueryWrapper qWrapper = Wrappers.lambdaQuery(); + qWrapper.eq(MchModifyApplymentEntity::getChannelApplyNo, channelApplyNo); + return mchInfoConverter.toModel(mchModifyApplymentService.getOne(qWrapper)); + } + + private void handleSuccessfulChange(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) { + MutablePair mchModifyPair; + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + mchModifyPair = isvmchModifyApplymentService.localModifyBase(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + mchModifyPair = isvmchModifyApplymentService.localModifySettlement(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + case MchModifyApplyment.MODIFY_TYPE_RATE: + mchModifyPair = isvmchModifyApplymentService.localModifyRate(new MutablePair<>(modifyApplyment, mchApplyment)); + break; + default: + mchModifyPair = new MutablePair<>(modifyApplyment, mchApplyment); + } + + updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight()); + } + + private void handleWaitingForSign(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, IIsvmchModifyApplymentService isvmchModifyApplymentService) { + MutablePair mchModifyPair = isvmchModifyApplymentService.queryModifyResult(new MutablePair<>(modifyApplyment, mchApplyment)); + updateModificationState(mchModifyPair.getLeft(), mchModifyPair.getRight()); + } + + private void handleRejectedState(MchModifyApplyment modifyApplyment, String note) { + MchModifyApplymentEntity result = new MchModifyApplymentEntity(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + result.setApplyErrorInfo("[" + note + "]"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + mchModifyApplymentService.updateById(result); + } + + private void updateModificationState(MchModifyApplyment modifyApplyment, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + MchModifyApplymentEntity dbEntity = mchInfoConverter.toDbEntity(modifyApplyment); + MchApplyment dbEntity1 = mchInfoConverter.toDbEntity(mchApplyment); + + // 状态变更就更新 + if (!modifyApplyment.getState().equals(mchApplyment.getState())) { + mchModifyApplymentService.updateById(dbEntity); + + // 变更成功就更新商户数据 + if (modifyApplyment.getState() == MchApplyment.STATE_SUCCESS) { + mchApplymentService.updateById(dbEntity1); + } + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..acf5d44 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchModifyApplymentService.java @@ -0,0 +1,343 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.YspayApplymentInfo; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + + +@Slf4j +@Service +public class YspayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + YspayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, YspayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + YspayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, YspayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setSettAccountType(mchModifyData.getSettAccountType()); + originMchModifyData.setIsUncrpSett(mchModifyData.getIllegal()); + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + originMchModifyData.setSettleAuthLetterPhoto(mchModifyData.getNonLegSettleAuthPic()); + originMchModifyData.setSettAccountIdcardNo(mchModifyData.getSettAccountIdcardNo()); + originMchModifyData.setSettAccountIdcard1Img(mchModifyData.getSettAccountIdcard1Img()); + originMchModifyData.setSettAccountIdcard2Img(mchModifyData.getSettAccountIdcard2Img()); + originMchModifyData.setSettAccountIdcardEffectBegin(mchModifyData.getSettAccountIdcardEffectBegin()); + originMchModifyData.setSettAccountIdcardEffectEnd(mchModifyData.getSettAccountIdcardEffectEnd()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put("notifyUrl", getCallbackUrl(mchApplyment.getIfCode(), mchApplyment.getApplyId())); + param.put("mercId", mchApplyment.getChannelMchNo()); + param.put("contractType", "2"); + param.put("changeThirdFlowId", mchModifyApplyment.getModifyApplyId()); + + JSONObject custInfo = new JSONObject(); + + custInfo.put("mercShortName", mchModifyData.getMchShortName()); + // 其他属性暂不考虑 + param.put("custInfo", custInfo); + + if (ObjectUtils.isEmpty(mchModifyData.getChangeFormPic())) { + // 使用电子变更申请表 + param.put("contractType", "2"); + } else { + // 使用纸质变更申请表 + param.put("contractType", "1"); + } + + try { + String respData = YspayKit.applymentRequest(ReqMethod.Method.CHANGE_MERC_BASE_INFO, isvParams, param); + JSONObject applyResp = JSON.parseObject(respData); + JSONObject applyRespData = applyResp.getJSONObject("data"); + + String changeSysFlowId = applyRespData.getString("changeSysFlowId"); + + resultModifyApplyment.setChannelApplyNo(changeSysFlowId); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String signUrl = applyRespData.getString("signUrl"); + if (!CharSequenceUtil.isEmpty(signUrl)) { + resultModifyApplyment.setState(MchApplyment.STATE_WAIT_SIGN); + } + + String remark = "银盛基本信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("云商服3.0基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + if (!ObjectUtils.isEmpty(mchModifyData.getChangeFormPic())) { + // 使用纸质变更申请表 + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getChangeFormPic(), "B008"); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + MchApplyment mchApplyment = mchDataPair.getValue(); + + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + JSONObject param = new JSONObject(); + param.put("notifyUrl", getCallbackUrl(mchApplyment.getIfCode(), mchApplyment.getApplyId())); + JSONObject stlAccInfo = new JSONObject(); + stlAccInfo.put("isSettInPlatAcc", "N"); + stlAccInfo.put("isUncrpSett", mchModifyData.getIllegal()); + stlAccInfo.put("stlAccNo", mchModifyData.getSettAccountNo()); + stlAccInfo.put("stlAccType", mchModifyData.getSettAccountType().equals("B")? "21": "11"); + stlAccInfo.put("openCertNo", mchModifyData.getSettAccountIdcardNo()); + stlAccInfo.put("stlAccNm", mchModifyData.getSettAccountName()); + stlAccInfo.put("bankSubCode", mchModifyData.getBankSubCode()); + stlAccInfo.put("bankMobile", mchModifyData.getPhone()); + + stlAccInfo.put("bankProince", mchModifyData.getSettAccountBankBranchAreaCode().getString(0)); + stlAccInfo.put("bankCity", mchModifyData.getSettAccountBankBranchAreaCode().getString(1)); + + param.put("stlAccInfo", stlAccInfo); + param.put("mercId", mchApplyment.getChannelMchNo()); + + if (ObjectUtils.isEmpty(mchModifyData.getChangeFormPic())) { + // 使用电子变更申请表 + param.put("contractType", "2"); + } else { + // 使用纸质变更申请表 + param.put("contractType", "1"); + } + + try { + String respData = YspayKit.applymentRequest(ReqMethod.Method.CHANGE_MERC_STL_ACC_INFO, isvParams, param); + JSONObject applyResp = JSON.parseObject(respData); + JSONObject applyRespData = applyResp.getJSONObject("data"); + + String changeSysFlowId = applyRespData.getString("changeSysFlowId"); + + resultModifyApplyment.setChannelApplyNo(changeSysFlowId); + resultModifyApplyment.setChannelVar1(applyRespData.toJSONString()); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + + String signUrl = applyRespData.getString("signUrl"); + if (!CharSequenceUtil.isEmpty(signUrl)) { + resultModifyApplyment.setState(MchApplyment.STATE_WAIT_SIGN); + } + + String remark = "银盛结算信息变更已发起"; + resultModifyApplyment.setRemark(remark); + log.debug("云商服3.0基本信息变更发起成功"); + } catch (Exception e) { + resultModifyApplyment.setApplyErrorInfo("[" + e.getMessage() + "]"); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + return new MutablePair<>(resultModifyApplyment, null); + } + + // 上传图片 + if ("B".equals(mchModifyData.getSettAccountType())) { + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getSettAccountLicenseImg(), "A011"); + } else { + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getSettAccountLicenseImg(), "A004"); + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getSettAccountLicenseImg(), "A005"); + } + + if ("Y".equals(mchModifyData.getIllegal())) { + // 非法人结算, 上传身份证图片 + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getSettAccountIdcard1Img(), "A013"); + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getSettAccountIdcard2Img(), "A014"); + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getNonLegSettleAuthPic(), "B005"); + } + + if (!ObjectUtils.isEmpty(mchModifyData.getChangeFormPic())) { + // 使用纸质变更申请表 + YspayKit.uploadEditRequest(resultModifyApplyment.getChannelApplyNo(), isvParams, mchModifyData.getChangeFormPic(), "B008"); + } + + return new MutablePair<>(resultModifyApplyment, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return mchDataPair; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + // 银盛的变更与本地修改保持一致 + return localModifySettlementType(mchDataPair); + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + + MchModifyApplyment modifyApplyment = mchDataPair.getLeft(); + resultModifyApplyment.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + MchApplyment mchApplyment = mchDataPair.getRight(); + + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + JSONObject param = new JSONObject(); + param.put("changeSysFlowId", modifyApplyment.getChannelApplyNo()); + + String respData = YspayKit.applymentRequest(ReqMethod.Method.QUERY_CUST_CHANGE, isvParams, param); + JSONObject bizData = JSON.parseObject(respData).getJSONObject("data"); + String status = bizData.getString("status"); + + switch (status) { + case "00": + // 成功 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + return handleSuccessCase(modifyApplyment, mchDataPair); + case "01": + // 待补充资料, 图片未上传 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_WAIT_VERIFY); + + return new MutablePair<>(resultModifyApplyment, null); + case "02": + // 待审核 + // 待签署电子变更申请表 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_AUDITING); + return new MutablePair<>(resultModifyApplyment, null); + case "03": + // 待签署电子变更申请表 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_WAIT_SIGN); + + return new MutablePair<>(resultModifyApplyment, null); + default: + // 失败 + resultModifyApplyment.setChannelVar1(processChannelValue(modifyApplyment.getChannelVar1(), bizData)); + resultModifyApplyment.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + resultModifyApplyment.setApplyErrorInfo("[" + bizData.getString("note") + "]"); + + return new MutablePair<>(resultModifyApplyment, null); + } + + } + + private MutablePair handleSuccessCase(MchModifyApplyment modifyApplyment, MutablePair mchDataPair) { + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + default: + return mchDataPair; + } + } + + private String processChannelValue(String channelVal, JSONObject bizData) { + JSONObject channelValJSON = StrUtil.isEmptyIfStr(channelVal) ? new JSONObject() : JSON.parseObject(channelVal); + ApplymentSignInfo signInfo = new ApplymentSignInfo(); + signInfo.setSignUrl(bizData.getString("signUrl")); + signInfo.setState("签约中"); + signInfo.setOriginData(bizData.toJSONString()); + channelValJSON.putAll(((JSONObject) JSON.toJSON(signInfo))); + + return channelValJSON.toJSONString(); + } + + + // 获取支付网关,用于进件回调 + protected String getCallbackUrl(String ifCode, String applyId) { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/mchApplyment/notify/" + ifCode + "/" + applyId; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchTerminalService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchTerminalService.java new file mode 100644 index 0000000..787e15e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchTerminalService.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchStoreTerminal; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchTerminalService; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class YspayIsvmchTerminalService implements IIsvmchTerminalService { + + @Override + public ChannelRetMsg sendup(MchStoreTerminal mchStoreTerminal, String isvNo, String mchNo, String mchAppId, String ifCode, boolean isSendup) { + + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams)configContextQueryService.queryIsvParams(isvNo, ifCode); + YspayIsvsubMchParams mchParams = (YspayIsvsubMchParams)configContextQueryService.queryIsvsubMchParams(mchNo, mchAppId, ifCode); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + try { + JSONObject bizContent = new JSONObject(); + + JSONArray infoList = new JSONArray(); + JSONObject info = new JSONObject(); + // 商户号 + info.put("mercId", mchParams.getMercId()); + //CUPS_WECHAT : 银联微信支付 + //CUPS_ALIPAY : 银联支付宝 + //CUPS_POS_SCANPAY : 银联云闪付 + //NUCC_WECHAT : 网联终端采集 + info.put("channelCode", "CUPS_POS_SCANPAY"); + // 00-新增 01-修改 02-注销 + info.put("operationType", isSendup?"00":"02"); + info.put("terminalType", "11"); + info.put("terminalNo", mchStoreTerminal.getTrmNo()); + info.put("terminalAddr", mchStoreTerminal.getDetailAddress()); + infoList.add(info); + + bizContent.put("terminalInfoList", infoList.toJSONString()); + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/report/scan/channel/terminalReport", "bindTerm", isvParams, bizContent); + JSONObject response = JSONObject.parseObject(resultStr); + JSONObject resData = response.getJSONObject("data"); + String code = resData.getString("code"); + if ("00".equals(code)) { + String trmNo = resData.getString("trmNo"); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + channelRetMsg.setChannelOrderId(trmNo); + return channelRetMsg; + } else { + log.error("【银盛终端报备】 请求失败:code={}, msg={}", code, resData.getString("note")); + channelRetMsg.setChannelErrMsg(resData.getString("note")); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + return channelRetMsg; + } + } catch (Exception e) { + log.error("【银盛终端报备】绑定终端设备失败", e); + channelRetMsg.setChannelErrMsg(e.getMessage()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + return channelRetMsg; + } + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWrapper.java new file mode 100644 index 0000000..9506943 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWrapper.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +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.applyment.YspayApplymentInfo; +import com.jeequan.jeepay.thirdparty.channel.AbsIsvmchWrapper; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Map; + +@Service("yspayIsvmchWrapper") +public class YspayIsvmchWrapper extends AbsIsvmchWrapper { + + /** + * 主要用于添加默认的D1, D0手续费 + * @param mchApplyment 商户信息 + */ + @Override + public Map channelInit(Map mchRateConfigMap, MchApplyment mchApplyment) { + + // 配置默认D1手续费 + if (mchRateConfigMap.get("D1") == null) { + PaywayFee paywayFee = new PaywayFee(); + paywayFee.setWayCode("D1"); + paywayFee.setFeeRate(BigDecimal.valueOf(0.0001)); + paywayFee.setFeeType(PaywayFee.FEE_TYPE_SINGLE); + paywayFee.setApplymentSupport(CS.YES); + mchRateConfigMap.put("D1", paywayFee); + } + + // 配置默认D0手续费 + if (mchRateConfigMap.get("D0") == null) { + PaywayFee paywayFee = new PaywayFee(); + paywayFee.setWayCode("D0"); + paywayFee.setFeeRate(BigDecimal.valueOf(0.001)); + paywayFee.setFeeType(PaywayFee.FEE_TYPE_SINGLE); + paywayFee.setApplymentSupport(CS.YES); + mchRateConfigMap.put("D1", paywayFee); + } + + return mchRateConfigMap; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWxConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWxConfigService.java new file mode 100644 index 0000000..7b1168a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayIsvmchWxConfigService.java @@ -0,0 +1,162 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchSubInfo; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.thirdparty.channel.IsvFactory; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class YspayIsvmchWxConfigService implements IIsvmchWxConfigService { + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Override + public ChannelRetMsg configPayBaseUrl(String configBaseUrl, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg applyModifyMchRate(List paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public String queryConfiguredInfo(String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configBindAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return null; + } + + @Override + public ChannelRetMsg configSubscribeAppId(String configAppId, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchShortName(String mchShortName, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ChannelRetMsg applyModifyMchAppPublicKey(String appPublicKey, String isvNo, String mchNo, String mchAppId, String ifCode) { + return ChannelRetMsg.confirmSuccess(null); + } + + @Override + public ApplymentSignInfo wxOpenSignInfo(MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + JSONObject suJson = JSON.parseObject(mchApplyment.getSuccResParameter()); + // 获取到 服务商配置信息 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + // 微信开通意愿二维码地址 + result.setSignUrl(isvParams.getWxOpenUrl()); + result.setImgType(ApplymentSignInfo.IMG_TYPE_QRCONTENT); + + // 同步后子商户信息还是为空,则抛出异常 + if (suJson == null || StringUtils.isEmpty(suJson.getString("mercId"))) { + result.setErrInfo("银盛商户号为空"); + return result; + } + // 银盛商户号 + String mercId = suJson.getString("mercId"); + + LambdaQueryChainWrapper wxSubInfoQuery = mchSubInfoService.lambdaQuery() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getChannelMchNo, mchApplyment.getChannelMchNo()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + MchSubInfoEntity wx = wxSubInfoQuery.one(); + + if (wx == null) { + IsvFactory.getIsvMchApplymentService(JeepayKit.getIfCodeOrigin(mchApplyment.getIfCode())) + .subMchColl(mchApplyment); + + wx = wxSubInfoQuery.one(); + } + + if (wx == null) { + result.setState("未报备"); + result.setErrInfo("[未获取到子商户信息]"); + return result; + } else if (!"00".equals(wx.getStatus())) { + result.setState("未报备"); + result.setErrInfo("[" + wx.getRemark() + "]"); + return result; + } else { + result.setChannelSubMchId(wx.getSubMchId()); + } + + // 请求参数 + JSONObject bizContent = new JSONObject(); + bizContent.put("mercId", mercId); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/trade/scan/wechat/auth/getAuthState", "trade.scan.wechat.auth.getAuthState", isvParams, bizContent); + JSONObject response = JSONObject.parseObject(resultStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState("04"); + result.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + return result; + } + +// String state = resData.getString("state"); +// +// // 请求异常 +// if(!"00".equals(state)){ +// result.setErrInfo(resData.getString("msg") + resData.getString("subMsg")); +// return result; +// } + // 授权状态 + String authorizeStat = resData.getString("authStateX"); + + LambdaUpdateChainWrapper stateUpdate = mchSubInfoService.lambdaUpdate() + .eq(MchSubInfoEntity::getMchApplyId, mchApplyment.getApplyId()) + .eq(MchSubInfoEntity::getMainUse, 1) + .eq(MchSubInfoEntity::getSubMchType, "WX"); + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authorizeStat)) { + result.setState("未授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_UNAUTHORIZED).update(); + } else if ("AUTHORIZE_STATE_AUTHORIZED".equals(authorizeStat)) { + result.setState("已授权"); + stateUpdate.set(MchSubInfoEntity::getAuthStatus, MchSubInfo.AUTH_STATUS_AUTHORIZED).update(); + } else { + result.setErrInfo(resData.getString("subMsg")); + result.setState(authorizeStat); + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApiService.java new file mode 100644 index 0000000..4131f4b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApiService.java @@ -0,0 +1,212 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +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.params.yspay.YspayIsvParams; +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 com.jeequan.jeepay.db.entity.SettleInfo; +import com.jeequan.jeepay.thirdparty.channel.AbstractMchApiService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * TODO + * + * @author crystal + * @date 2023/12/4 10:47 + */ +@Service +@Slf4j +public class YspayMchApiService extends AbstractMchApiService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public boolean preCheck() { + return true; + } + + /** + * + * @param applyment + * @param mchRq + * @return + */ + @Override + public ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq) { + ReqMethod.Method method = ReqMethod.Method.APPID_ADD_OR_UPDATE; + JSONObject bizData = new JSONObject(); + //默认配置银联 + bizData.put("channelId","CUPS_WECHAT"); + bizData.put("mercId",applyment.getChannelMchNo()); + if(ChannelMchRq.Type.PATH.getType().equals(mchRq.getType())){ + bizData.put("payAuthPath",mchRq.getJsapiPath()); + method = ReqMethod.Method.AUTH_PATH_ADD; + }else if(ChannelMchRq.Type.PUBLIC.getType().equals(mchRq.getType())){ + bizData.put("jsPayRelatedAppId",mchRq.getAppid()); + }else{ + bizData.put("appletId",mchRq.getAppid()); + } + + YspayIsvParams yspayIsvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(applyment); + + JSONObject respBizData = YspayKit.reqV3(method, yspayIsvParams, bizData); + ChannelRetMsg retMsg = new ChannelRetMsg(); + retMsg.setChannelBizData(respBizData); + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + return retMsg; + } + + @Override + public List querySettleInfo(ChannelSettleRq settleRq, String isvNo, YspayIsvParams isvParams) { + super.preSettleCheck(settleRq); + ReqMethod.Method method = ReqMethod.Method.QUERY_SETTLE; + JSONObject bizData = new JSONObject(); + if(settleRq.getMercNos() != null && !settleRq.getMercNos().isEmpty()){ + bizData.put("mercIds",settleRq.getMercNos()); + } + if(StringUtils.isNotBlank(settleRq.getMercNo())){ + bizData.put("mercId",settleRq.getMercNo()); + } + if(StringUtils.isNotEmpty(settleRq.getBillNo())){ + bizData.put("stlBillNo",settleRq.getBillNo()); + }else{ + bizData.put("pageNum",settleRq.getPage()); + bizData.put("pageSize",settleRq.getSize()); + if(settleRq.getStartDate() != null){ + bizData.put("startFactPayDate",DateUtil.format(settleRq.getStartDate(), DatePattern.PURE_DATE_PATTERN)); + } + if(settleRq.getEndDate() != null){ + bizData.put("endFactPayDate", DateUtil.format(settleRq.getEndDate(), DatePattern.PURE_DATE_PATTERN)); + } + } + JSONObject respBizData = YspayKit.reqV3(method, isvParams, bizData); + JSONArray infos = respBizData.getJSONArray("infos"); + if(infos == null || infos.isEmpty()){ + return null; + } + List result = new ArrayList<>(infos.size()); + infos.forEach(item -> { + JSONObject itemData = ((JSONObject) item); + JSONObject data = new JSONObject(); + data.put("billNo",itemData.getString("stlBillNo")); + data.put("isvNo", isvNo); + data.put("accountNo",itemData.getString("accountNo")); + data.put("accountName",itemData.getString("accountName")); + data.put("settleType","D1"); + if(StringUtils.isNotBlank(itemData.getString("stlAmt"))){ + long stlAmt = itemData.getBigDecimal("stlAmt").multiply(BigDecimal.valueOf(100)).longValue(); + data.put("settleAmt",stlAmt); + } +// if(StringUtils.isNotBlank(itemData.getString("mercServiceAmt"))){ +// long feeAmt = itemData.getBigDecimal("mercServiceAmt").multiply(BigDecimal.valueOf(100)).longValue(); +// data.put("fee",feeAmt); +// } + SettleState payState = SettleState.getVal(itemData.getString("payState")); + switch (payState){ + case PAY_SUCCESS: + data.put("state", SettleInfo.SUCCESS); + break; + case PAY_PROGRESS: + data.put("state", SettleInfo.PROGRESS); + break; + case PAY_FAIL: + data.put("state", SettleInfo.FAIL); + break; + case PAY_ACCOUNT_FAIL: + data.put("state", SettleInfo.FAIL); + break; + case PAY_SUSPEND: + data.put("state", SettleInfo.SUSPEND); + break; + case PAY_FREEZE: + data.put("state", SettleInfo.FREEZE); + break; + case PAY_TICKET: + data.put("state", SettleInfo.TICKET); + break; + default: + data.put("state", SettleInfo.WAIT); + break; + } + data.put("channelState",payState.getState()); + data.put("channelCode",itemData.getString("retrunCode")); + data.put("remark",itemData.getString("retrunMsg")); + data.put("bankName",itemData.getString("bankName")); + String payDate = itemData.getString("payDate"); + if(StringUtils.isNotBlank(payDate)){ + data.put("settleDate",DateUtil.format(DateUtil.parse(payDate,DatePattern.PURE_DATE_PATTERN),DatePattern.NORM_DATE_PATTERN)); + } + Long payStateTime = itemData.getLong("payStateTime"); + data.put("settleTime",new Date(payStateTime)); + data.put("extra", itemData.toString()); + result.add(data); + }); + return result; + } + + @Getter + @AllArgsConstructor + public enum SettleState{ + + PAY_WAIT_ACCOUNT("01","待记账"), + + PAY_PROGRESS("02","付款中"), + + PAY_SUCCESS("00","付款成功"), + + PAY_CANCEL("03","作废"), + + PAY_FAIL("04","付款失败"), + + PAY_NO("05","无需付款"), + + PAY_SUSPEND("06","暂缓"), + + PAY_FREEZE("07","冻结"), + + PAY_ACCOUNT_FAIL("08","记账失败"), + + PAY_WAIT("09","等待付款"), + + PAY_TICKET("10","已退票"); + + private final String state; + + private final String desc; + + public static SettleState getVal(String state){ + SettleState[] values = values(); + for (SettleState val:values) { + if(val.getState().equals(state)){ + return val; + } + } + return PAY_WAIT; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApplymentService.java new file mode 100644 index 0000000..1a72212 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayMchApplymentService.java @@ -0,0 +1,704 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.YspayApplymentInfo; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchSubInfoEntity; +import com.jeequan.jeepay.service.impl.MchSubInfoService; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.ApplymentNotify; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +import java.util.*; + +/** + * 银盛 接口进件 3.0 + * + * @author xiaoyu + * @date 2022/6/7 10:23 + */ +@Service +@Slf4j +public class YspayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + protected SysConfigService sysConfigService; + + @Autowired + private YspayApplymentApiService yspayApplymentApiService; + + @Autowired + private MchSubInfoService mchSubInfoService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment firstApplyment(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String logPrefix = "【银盛商户进件】"; + com.jeequan.jeepay.core.entity.MchApplyment result = new com.jeequan.jeepay.core.entity.MchApplyment(); + + // 获取支付参数 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode()); + + Assert.notNull(mchApplyment.getApplyId(), "商户号[applyId]不能为空"); + + try { + // 获取详细参数 + YspayApplymentInfo info = JSON.parseObject(mchApplyment.getApplyDetailInfo(), YspayApplymentInfo.class); + + Map picMap = new HashMap<>(); + + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContentApplyment(picMap, info, bizContent, isvParams, mchApplyment); + + bizContent.put("sysFlowId", mchApplyment.getChannelApplyNo()); + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/t1/smsc/addCustInfoApply", "t1.smsc.addCustInfoApply", isvParams, bizContent); + + JSONObject response = JSON.parseObject(resultStr); + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, response.getString("code"), response.getString("msg")); + return result; + } + + String channelOrderNo = resData.getString("sysFlowId"); + if (StringUtils.isNotEmpty(channelOrderNo)) { + result.setChannelApplyNo(channelOrderNo); + } + + // 完成第一步信息提交之后,保存流水号和剩余发起进件步骤数 + result.setApplyId(mchApplyment.getApplyId()); + result.setSettlementType(info.getSettAccountCut()); + result.setState(MchApplyment.STATE_AUDITING_WAIT); + result.setRemainStep(((byte) 2)); + result.setChannelMchNo(channelOrderNo); + result.setChannelVar1(resData.toJSONString()); + + // 后续操作由进件调度程序去处理 + return result; + } catch (Exception e) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + e.getMessage() + "]"); + log.error("{} 进件失败:", logPrefix, e); + } + return result; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment rejectModify(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + // 这里直接调用新增的接口 + return firstApplyment(mchApplyment); + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment replenishInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return null; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment query(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String logPrefix = "【银盛商户进件状态查询】"; + com.jeequan.jeepay.core.entity.MchApplyment result = new com.jeequan.jeepay.core.entity.MchApplyment(); + result.setState(mchApplyment.getState()); + result.setApplyId(mchApplyment.getApplyId()); + + if (mchApplyment.getState() == com.jeequan.jeepay.core.entity.MchApplyment.STATE_AUDITING) { + // 资料确认状态查询 + // 获取支付参数 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContent.put("sysFlowId", mchApplyment.getChannelApplyNo()); + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/smsc/queryCustApply", "smsc.queryCustApply", isvParams, bizContent); + JSONObject response = JSON.parseObject(resultStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo(response.getString("code") + "[" + response.getString("note") + "]"); + log.error("{} 请求失败:code={}, msg={}", logPrefix, response.getString("code"), response.getString("note")); + return result; + } + + String applStatus = resData.getString("status"); + + mchApplyment.setChannelVar1(resData.toJSONString()); + + // 审核成功 + if ("00".equals(applStatus)) { + return signApply(mchApplyment); + } + // 审核拒绝 + else if ("90".equals(applStatus)) { + result.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + resData.getString("note") + "]"); + return result; + + } else { + result.setApplyErrorInfo("[" + resData.getString("note") + "]"); + return result; + } + } + + if (mchApplyment.getState() == com.jeequan.jeepay.core.entity.MchApplyment.STATE_WAIT_SIGN) { + return yspayApplymentApiService.signQuery(mchApplyment); + } + + return mchApplyment; + } + + @Override + public com.jeequan.jeepay.core.entity.MchApplyment signApply(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + String applyDetailInfo = mchApplyment.getApplyDetailInfo(); + + return yspayApplymentApiService.signApply(JSON.parseObject(applyDetailInfo), mchApplyment); + } + + /** + * 获取签约地址 + */ + @Override + public ApplymentSignInfo signInfo(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + + ApplymentSignInfo result = new ApplymentSignInfo(); + + try { + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + // 1、获取当前进件签约信息,未发起签约时为空 + String channelVar2 = mchApplyment.getChannelVar2(); + + // 2、未发起签约 + if (StringUtils.isBlank(channelVar2)) { + result.setState("01"); + return result; + } + + // 3、查询数据库签约状态 + ApplymentSignInfo dbSignInfo = JSON.parseObject(channelVar2, ApplymentSignInfo.class); + + // 4、调渠道接口,查询签约状态 + JSONObject queryJSON = new JSONObject(); + JSONObject channelSignJSON = JSON.parseObject(dbSignInfo.getOriginData()); + queryJSON.put("authId", channelSignJSON.getString("authId")); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/smsc/saas/constract/queryAuthInfo", "smsc.saas.constract.queryAuthInfo", isvParams, queryJSON); + JSONObject response = JSON.parseObject(resultStr); + + // 解密后数据 + JSONObject resData = response.getJSONObject("data"); + if (resData == null) { + result.setState("04"); + result.setErrInfo(response.getString("code") + "[" + response.getString("msg") + "]"); + return result; + } + + result.setState(resData.getString("status")); + result.setErrInfo(resData.getString("note")); + + if ("00".equals(resData.getString("status"))) { + result.setState("签约成功"); // 前端直接展示文字 + } + return result; + + } catch (Exception e) { + result.setSignUrl("签约信息解析异常" + e.getMessage()); + return result; + } + } + + /*@Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + ApplymentSignInfo result = new ApplymentSignInfo(); + try { + + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), CS.IF_CODE.YSPAY); + + // 获取签约地址 + String channelVar2 = mchApplyment.getChannelVar2(); + if (StringUtils.isEmpty(channelVar2)) { + result.setErrInfo("签约信息为空"); + } + JSONObject signJson = JSON.parseObject(channelVar2); + // 签约地址 + String signUrl = signJson.getString("signUrl"); + // 签约流水号 + String sysSignFlowId = signJson.getString("sysSignFlowId"); + if (StringUtils.isEmpty(signUrl) || StringUtils.isEmpty(sysSignFlowId)) { + result.setErrInfo("签约地址或签约流水号不能为空"); + } + result.setSignUrl(signUrl); + // 查询签约状态 + JSONObject bizContent = new JSONObject(); + // 请求参数 + bizContent.put("sysSignFlowId", sysSignFlowId); + // 发送请求 + String resultStr = YspayKit.applymentRequest("/saas/orgSign/querySignSts", "querySignSts", isvParams, bizContent); + JSONObject response = JSON.parseObject(resultStr); + JSONObject resData = response.getJSONObject("data"); + // 原参数 + result.setOriginData(resData.toJSONString()); + // 响应状态 + String code = resData.getString("code"); + if ("00".equals(code)) { + String signState = resData.getString("signSts"); + if (StringUtils.isNotEmpty(signState)) { + if ("0".equals(signState)) { + result.setState("申请中"); + } else if ("1".equals(signState)) { + result.setState("待签署"); + } else if ("2".equals(signState)) { + result.setState("已签约"); + } else if ("3".equals(signState)) { + result.setState("已作废"); + } else if ("4".equals(signState)) { + result.setState("已过期"); + } else if ("7".equals(signState)) { + result.setState("待签署"); + } else if ("8".equals(signState)) { + result.setState("合同已生成"); + } + } + } else { + result.setState("|"); + result.setErrInfo(resData.getString("note")); + log.error("请求失败:code={}, msg={}", code, resData.getString("note")); + return result; + } + + } catch (Exception e) { + result.setSignUrl("签约信息解析异常" + e.getMessage()); + } + return result; + }*/ + public void bizContentApplyment(Map picMap, YspayApplymentInfo info, JSONObject bizContent, YspayIsvParams isvParams, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + // 费率校验 + YspayApplymentInfo.convertFeeJSON(info.getPaywayFeeList(), isvParams.getSettType()); + + // 基本信息 + bizContent.put("custInfo", setCustInfo(picMap, info, isvParams, mchApplyment)); + // 法人信息 + bizContent.put("crpInfo", setCrpInfo(picMap, info)); + // 结算信息 + bizContent.put("stlAccInfo", setStlAccInfo(picMap, info)); + // 营业信息 + bizContent.put("busInfo", setBusInfo(picMap, info)); + } + + // 获取支付网关,用于进件回调 + protected String getApplySiteUrl() { + return sysConfigService.getDBApplicationConfig().getPaySiteUrl(); + } + + /** + * 基本信息 + **/ + private JSONObject setCustInfo(Map picMap, YspayApplymentInfo info, YspayIsvParams isvParams, com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + JSONObject custInfoJson = new JSONObject(); + // 服务商编号 + custInfoJson.put("agtMercId", isvParams.getAgtMercId()); + // 商户名称 + + custInfoJson.put("mercName", info.getMchFullName()); + if (ObjectUtils.isEmpty(info.getMchFullName())) { + throw new BizException("商户全称不能为空"); + } + // 商户简称 + if (StringUtils.isNotEmpty(info.getMchShortName())) { + custInfoJson.put("mercShortName", info.getMchShortName()); + } + // 商户类型,2 小微 3个体 4企业 5 社会组织 6 事业单位 7 政府机关 + custInfoJson.put("mercType", info.getYsMerchantType()); + // MCC码 + custInfoJson.put("mccCd", info.getMccCode()); + // 联系人电话 + custInfoJson.put("contactPhone", info.getContactPhone()); + // 联系人邮箱 + custInfoJson.put("contactMail", "18062761507@163.com"); + // 联系人姓名 + custInfoJson.put("contactMan", info.getContactName()); + // 客户经理姓名 + custInfoJson.put("cusMgrNm", isvParams.getCusMgrNm()); + // 是否开通营销,Y开通N不开通,默认不开通 + custInfoJson.put("isOpenMarket", "N"); + // 异步通知地址 + custInfoJson.put("notifyUrl", getApplySiteUrl() + "/api/mchApplyment/notify/" + mchApplyment.getIfCode() + "/" + mchApplyment.getApplyId()); + + // 门头照 + picMap.put("A006", info.getStoreOuterImg()); + // 内景照 + picMap.put("A007", info.getStoreInnerImg()); + // 收银台照 + picMap.put("A008", info.getStoreCashierImg()); + return custInfoJson; + } + + /** + * 法人信息 + **/ + private JSONObject setCrpInfo(Map picMap, YspayApplymentInfo info) { + JSONObject crpInfoJson = new JSONObject(); + // 法人证件类型,00:身份证 06:国外护照 07:港澳通行证 08:台胞通行证 + crpInfoJson.put("crpCertType", "00"); + // 法人姓名 + crpInfoJson.put("crpNm", info.getIdcardName()); + // 法人身份证号 + crpInfoJson.put("crpCertNo", info.getIdcardNo()); + // 法人身份证开始日期 + crpInfoJson.put("certBgn", info.convertDate(info.getIdcardEffectBegin())); + // 法人身份证结束日期 + crpInfoJson.put("certExpire", info.convertDate(info.getIdcardEffectEnd())); + // 法人电话 + crpInfoJson.put("crpPhone", info.getLegalPersonPhone()); + // 法人地址 + crpInfoJson.put("crpAddr", info.getIdcardAddress()); + // 法人身份证正面 + picMap.put("A002", info.getIdcard1Img()); + // 法人身份证背面 + picMap.put("A003", info.getIdcard2Img()); + + // 被授权人信息,非法人结算同开户人信息 + if ("Y".equals(info.getIsUncrpSett())) { + JSONObject authInfo = new JSONObject(); + // 被授权人姓名 + authInfo.put("name", info.getSettAccountName()); + // 被授权人证件类型 + authInfo.put("certType", "00"); + // 被授权人证件号 + authInfo.put("certNo", info.getSettAccountIdcardNo()); + // 被授权人证件起始日期,格式:YYYYMMDD + authInfo.put("certBgn", info.convertDate(info.getSettAccountIdcardEffectBegin())); + // 被授权人证件有效期,格式:YYYYMMDD + authInfo.put("certExpire", info.convertDate(info.getSettAccountIdcardEffectEnd())); + // 被授权人证件地址 + authInfo.put("addr", info.getSettleAuthAddress()); + // 被授权人身份证正面 + picMap.put("A013", info.getSettAccountIdcard1Img()); + // 被授权人身份证背面 + picMap.put("A014", info.getSettAccountIdcard1Img()); + // 非法人结算授权函 + picMap.put("B005", info.getSettleAuthLetterPhoto()); + + + crpInfoJson.put("authInfo", authInfo); + } + + return crpInfoJson; + } + + /** + * 结算信息 + **/ + private JSONObject setStlAccInfo(Map picMap, YspayApplymentInfo info) { + JSONObject stlAccJson = new JSONObject(); + // 是否平台内账户,Y是 N否,默认否 + stlAccJson.put("isSettInPlatAcc", "N"); + // 是否非法人结算,Y是 N否,默认否 + stlAccJson.put("isUncrpSett", info.getIsUncrpSett()); + // 结算户名,默认法人姓名 + stlAccJson.put("stlAccNm", StringUtils.defaultString(info.getDiySettAccountName(), info.getIdcardName())); + // 开户证件号,默认法人证件号 + stlAccJson.put("openCertNo", info.getIdcardNo()); + // 结算账号 + stlAccJson.put("stlAccNo", info.getSettAccountNo()); + // 开户支行联行号 + stlAccJson.put("bankSubCode", info.getBankSubCode()); + // 结算账户类型,11 对私 21 对公 23 对公存折 24 单位结算卡 + stlAccJson.put("stlAccType", info.getYsSettAccountType(info.getSettAccountType())); + if (com.jeequan.jeepay.core.entity.MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(info.getSettAccountType())) { + picMap.put("A011", info.getCompanyAccountLicenseImg()); + } else { + picMap.put("A004", info.getSettAccountLicenseImg()); + picMap.put("A005", info.getSettAccountLicenseImg()); + } + + // 非法人结算 + if ("Y".equals(info.getIsUncrpSett())) { + // 结算户名,默认法人姓名, 非法人结算必填 + stlAccJson.put("stlAccNm", info.getSettAccountName()); + // 银行预留手机号 + stlAccJson.put("bankMobile", info.getBankMobile()); + // 开户证件号 + stlAccJson.put("openCertNo", info.getSettAccountIdcardNo()); + if (info.getSettAccountBankBranchAreaCode().size() > 1) { + // 开户行省 + stlAccJson.put("bankProince", info.getSettAccountBankBranchAreaCode().get(0) + ""); + // 开户行市 + stlAccJson.put("bankCity", info.getSettAccountBankBranchAreaCode().get(1) + ""); + } + } + + // 备用结算信息 + if (StringUtils.isNotEmpty(info.getIsOtherAccountInfo()) && "1".equals(info.getIsOtherAccountInfo())) { + // 结算账户类型,11 对私 21 对公 23 对公存折 24 单位结算卡 + stlAccJson.put("standByStlAccType", info.getYsSettAccountType(info.getStandByStlAccType())); + // 银行预留手机号 + stlAccJson.put("standByStlAccNo", info.getStandByStlAccNo()); + // 备用账户户名 + stlAccJson.put("standByStlAccNm", info.getStandByStlAccNm()); + // 备用账户开户行支行编号 + stlAccJson.put("standByBankSubCode", info.getStandByBankSubCode()); + + if (info.getStandByAccountBankBranchAreaCode().size() > 1) { + // 备用账户开户行省 + stlAccJson.put("standByBankProvince", info.getStandByAccountBankBranchAreaCode().get(0) + ""); + // 备用账户开户行市 + stlAccJson.put("standByBankCity", info.getStandByAccountBankBranchAreaCode().get(1) + ""); + } + } + return stlAccJson; + } + + /** + * 营业信息 + **/ + private JSONObject setBusInfo(Map picMap, YspayApplymentInfo info) { + JSONObject busInfoJson = new JSONObject(); + /** 营业资质信息 【小微不传】**/ + if (!info.isPersonal()) { + // 营业执照名称 + busInfoJson.put("busNm", info.getMchFullName()); + // 营业执照号码 + busInfoJson.put("busNo", info.getLicenseNo()); + // 营业执照开始日期 + busInfoJson.put("busCertBgn", info.convertDate(info.getLicenseEffectBegin())); + // 营业执照结束日期 + busInfoJson.put("busCertExpire", info.convertDate(info.getLicenseEffectEnd())); + // 营业执照证件类型 个体及企业商户:仅支持 19:社会统一信用代码 + busInfoJson.put("busCertType", "19"); + } + // 营业详细地址,需包含省市区 + busInfoJson.put("busAddr", info.getAddress()); + + Assert.notNull(info.getAreaCode(), "营业省市区信息不能为空"); + // 营业归属省代码 + busInfoJson.put("busProviceCode", info.getAreaCode().get(0) + ""); + // 营业归属市代码 + busInfoJson.put("busCityCode", info.getAreaCode().get(1) + ""); + // 营业归属区(县)代码 + if (info.getAreaCode().get(2) != null) { + busInfoJson.put("busAreaCode", info.getAreaCode().get(2) + ""); + } + + picMap.put("A001", info.getLicenseImg()); + + return busInfoJson; + } + + @Override + public void subMchColl(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + if (mchApplyment.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS + && mchApplyment.getState() != com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY) { + return; + } + + // 获取到 渠道商配置信息 + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + List channelIdList = Arrays.asList("CUPS_WECHAT", "CUPS_ALIPAY", "NUCC_WECHAT", "NUCC_ALIPAY"); + + for (String channelId : channelIdList) { + JSONObject bizContent = new JSONObject(); + bizContent.put("mercId", mchApplyment.getChannelMchNo()); + bizContent.put("channelId", channelId); + String bizResult = YspayKit.applymentRequest("/openapi/report/scan/union/repAndAppIdQry", "report.scan.union.repAndAppIdQry", isvParams, bizContent); + JSONObject bizJSON = JSON.parseObject(bizResult).getJSONObject("data"); + + String apprSts = bizJSON.getString("apprSts"); + + String thirdMercId = bizJSON.getString("thirdMercId"); + + MchSubInfoEntity subInfo = new MchSubInfoEntity(); + subInfo.setSubMchId(thirdMercId); + subInfo.setMchApplyId(mchApplyment.getApplyId()); + subInfo.setSubMchWay(channelId); + subInfo.setStatus(apprSts); + + if (channelId.endsWith("WECHAT")) { + subInfo.setSubMchType("WX"); + } else if (channelId.endsWith("ALIPAY")) { + subInfo.setSubMchType("ZFB"); + } + + if (channelId.startsWith("CUPS")) { + subInfo.setMainUse(1); + } else { + subInfo.setMainUse(0); + } + + try { + mchSubInfoService.save(subInfo); + } catch (DuplicateKeyException ignored) { + // 主键冲突直接忽略 + } + } + } + + @Override + public void subMchColl(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, Object callback) { + ApplymentNotify.Report applymentNotify = (ApplymentNotify.Report) callback; + String channelMchNo = applymentNotify.getMercId(); + + List resultList = new ArrayList<>(); + for (ApplymentNotify.ThirdMerc thirdMerc : applymentNotify.getThridMercList()) { + + String apprSts = thirdMerc.getApprSts(); + String thridMercId = thirdMerc.getThridMercId(); + String remark = thirdMerc.getRemark(); + String reportChannel = thirdMerc.getReportChannel(); + + if (reportChannel.contains("POS")) { + continue; + } + + MchSubInfoEntity subInfo = new MchSubInfoEntity(); + subInfo.setChannelMchNo(channelMchNo); + subInfo.setSubMchId(Optional.ofNullable(thridMercId).orElse("报备失败")); + subInfo.setStatus(apprSts); + subInfo.setRemark(remark); + subInfo.setMainUse(0); + subInfo.setMchApplyId(mchApplyment.getApplyId()); + + subInfo.setSubMchWay(reportChannel); + if (reportChannel.contains("WECHAT")) { + subInfo.setSubMchType("WX"); + } + + if (reportChannel.contains("ALIPAY")) { + subInfo.setSubMchType("ZFB"); + } + + if (reportChannel.contains("CUPS")) { + subInfo.setMainUse(1); + } else { + subInfo.setMainUse(0); + } + + resultList.add(subInfo); + } + + if (!resultList.isEmpty()) { + mchSubInfoService.saveBatch(resultList); + } + } + + @Override + public void subMchCert(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, com.jeequan.jeepay.core.entity.MchSubInfo mchSubInfo) { + if ("WX".equals(mchSubInfo.getSubMchType())) { + wxMchCert(mchApplyment, mchSubInfo); + } + + if ("ZFB".equals(mchSubInfo.getSubMchType())) { + zfbMchCert(mchApplyment, mchSubInfo); + } + } + + private void zfbMchCert(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, com.jeequan.jeepay.core.entity.MchSubInfo mchSubInfo) { + JSONObject bizContent = new JSONObject(); + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + bizContent.put("mercId", mchApplyment.getChannelMchNo()); + + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String bizResult = YspayKit.applymentRequest("/openapi/pregate/alipay/getAuthState", "trade.scan.wechat.auth.getAuthState", isvParams, bizContent); + JSONObject bizJson = JSON.parseObject(bizResult); + + String state = bizJson.getString("state"); + + if (!"00".equals(state)) { + throw new BizException(state); + } + + String authState = bizJson.getString("authState"); + if ("1".equals(authState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + + if ("0".equals(authState)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } + + private void wxMchCert(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, com.jeequan.jeepay.core.entity.MchSubInfo mchSubInfo) { + JSONObject bizContent = new JSONObject(); + bizContent.put("mercId", mchApplyment.getChannelMchNo()); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + String bizResult = YspayKit.applymentRequest("/openapi/trade/scan/wechat/auth/getAuthState", "trade.scan.wechat.auth.getAuthState", isvParams, bizContent); + JSONObject bizJson = JSON.parseObject(bizResult); + + String state = bizJson.getString("state"); + + LambdaUpdateWrapper uWrapper = Wrappers.lambdaUpdate(); + + if (!"00".equals(state)) { + throw new BizException(state); + } + + String thirdMercIdX = bizJson.getString("thirdMercIdX"); + + if (mchSubInfo.getSubMchId().equals(thirdMercIdX)) { + String authStateX = bizJson.getString("authStateX"); + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authStateX)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authStateX)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + } + + String thirdMercIdY = bizJson.getString("thirdMercIdY"); + if (mchSubInfo.getSubMchId().equals(thirdMercIdY)) { + String authStateY = bizJson.getString("authStateY"); + if ("AUTHORIZE_STATE_AUTHORIZED".equals(authStateY)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_AUTHORIZED); + } + + if ("AUTHORIZE_STATE_UNAUTHORIZED".equals(authStateY)) { + uWrapper.set(MchSubInfoEntity::getAuthStatus, com.jeequan.jeepay.core.entity.MchSubInfo.AUTH_STATUS_UNAUTHORIZED); + } + } + + uWrapper.eq(MchSubInfoEntity::getMainUse, 1); + uWrapper.eq(MchSubInfoEntity::getMchApplyId, mchSubInfo.getMchApplyId()); + uWrapper.eq(MchSubInfoEntity::getSubMchType, mchSubInfo.getSubMchType()); + uWrapper.eq(!ObjectUtils.isEmpty(mchSubInfo.getSubMchWay()), MchSubInfoEntity::getSubMchWay, mchSubInfo.getSubMchWay()); + + mchSubInfoService.update(null, uWrapper); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderCloseService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderCloseService.java new file mode 100644 index 0000000..09641ba --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderCloseService.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderCloseService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 关闭订单接口实现类 + * + * @author xiaoyu + * + * @date 2022/5/16 9:09 + */ +@Slf4j +@Service +public class YspayPayOrderCloseService implements IPayOrderCloseService { + + @Override + public ChannelRetMsg close(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + try { + JSONObject bizContent = new JSONObject(); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + + String result = YspayKit.payRequest("ysepay.online.trade.close", mchAppConfigContext, bizContent, null, payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_trade_close_response"); + String code = response.getString("code"); + if (YspayKit.RES_CODE.equals(code)) { + String transNo = response.getString("trade_no"); + return ChannelRetMsg.confirmSuccess(transNo); + } + return ChannelRetMsg.waiting(); + }catch (Exception e) { + return ChannelRetMsg.sysError(e.getMessage()); + } + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderQueryService.java new file mode 100644 index 0000000..d937a73 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPayOrderQueryService.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 查询订单 银盛支付 + * + * @author xiaoyu + * + * @date 2022/4/15 14:29 + */ +@Service +@Slf4j +public class YspayPayOrderQueryService implements IPayOrderQueryService { + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + try { + JSONObject bizContent = new JSONObject(); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + + String result = YspayKit.payRequest("ysepay.online.trade.order.query", mchAppConfigContext, bizContent, null, payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_trade_order_query_response"); + String code = response.getString("code"); + if (YspayKit.RES_CODE.equals(code)) { + String tradeStatus = response.getString("trade_status"); + if(YspayKit.TRADE_SUCCESS.equals(tradeStatus)){ // 支付成功 + + String transNo = response.getString("trade_no"); + // 渠道流水号 + String channelRecvSn = response.getString("channel_recv_sn"); + // 商户订单号 + String channelSendSn = response.getString("channel_send_sn"); + // 卡类型 + String cardType = response.getString("card_type"); + YsCardType val = YsCardType.getVal(cardType); + String drType = CS.DrType.OTHER.getType(); + if(val != null){ + switch (val){ + case CREDIT: + drType = CS.DrType.CREDIT.getType(); + break; + case DEBIT: + drType = CS.DrType.DEBIT.getType(); + break; + } + } + return ChannelRetMsg.confirmSuccess(transNo, channelRecvSn, channelSendSn,drType); + + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + // 失败 + return ChannelRetMsg.confirmFail(); + } + } + //支付中 + return ChannelRetMsg.waiting(); + }catch (Exception e) { + //支付中 + return ChannelRetMsg.waiting(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPaymentService.java new file mode 100644 index 0000000..8d534ed --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayPaymentService.java @@ -0,0 +1,90 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Slf4j +@Service +public class YspayPaymentService extends AbstractPaymentService { + + /** + * 为了防止手续费的问题 限制银盛的最少支付金额为0.1元 + */ + public Long MIN_PAY_AMT = 10L; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + if(payOrder.getAmount() < MIN_PAY_AMT){ + throw new BizException("银盛通道最少需要支付0.1元"); + } + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + /** 支付下单分账登记 -服务商为商户分账下单模式 **/ + public void payOrderDivision(MchAppConfigContext mchAppConfigContext, PayOrder payOrder){ + YspayIsvParams mchParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + // 分账模式下走该逻辑 + if (mchParams.getPayType() != null && mchParams.getPayType().equals(YspayIsvParams.PAY_TYPE_DIVISION)) { + JSONObject bizContent = new JSONObject(); + // 订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 收款商户号 + bizContent.put("payee_usercode", mchAppConfigContext.getMchApplyment().getChannelMchNo()); + // 原交易订单金额 20长度位,保留2位小数 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt()+"")); + // 原订单是否参与分账 01:是,02否 + bizContent.put("is_divistion", "02"); + // 是否重新分账 Y:是,N:否 + bizContent.put("is_again_division", "N"); + // 分行模式 01 :比例,02:金额 + bizContent.put("division_mode", "02"); + // 发起分账请求 + String result = YspayKit.divisionRequest(YspayKit.DIVISION_URL, "ysepay.single.division.online.accept", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, null, payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_single_division_online_accept_response"); + log.info("【银盛】分账登记接口:response:{}", response); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayRefundService.java new file mode 100644 index 0000000..f66fe6b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/YspayRefundService.java @@ -0,0 +1,177 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.stereotype.Service; + +/** + * 退款接口: 银盛支付 + * + * @author xiaoyu + * + * @date 2022/4/15 9:34 + */ +@Service +public class YspayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.YSPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + ChannelRefundLimit refundLimit = this.isRefundLimit(payOrder.getSettleType(),payOrder.getMchExtNo()); + if(refundLimit.getIsPlatAccount()){ + this.checkPlatAccount(refundOrder); + } + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + JSONObject response = null; + String code = null; + YspayIsvsubMchParams mchParams = (YspayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), payOrder.getIfCode()); + // 如果为分账模式下单。走分账退款 + if (mchParams.getPayType() != null && mchParams.getPayType().equals(YspayIsvsubMchParams.PAY_TYPE_DIVISION)) { + // 商户原交易订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 商户系统的交易发生日期格式yyyyMMdd 示例值:20180525 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 银盛原交易流水号 + bizContent.put("trade_no", payOrder.getChannelOrderNo()); + // 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数,Number(10,2)指10位长度,2位精度 + bizContent.put("refund_amount", AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount()+"")); + // 退款的原因说明,该参数最长为50个汉字。 + bizContent.put("refund_reason", "分账退款"); + // 标商户系统生成的退款订单号,标识一次退款请求,同一笔交易多次退款需要保证唯一。 + bizContent.put("out_request_no", refundOrder.getRefundOrderId()); + // 原交易是否参与分账(01或空代表是,02代表否) + bizContent.put("is_division", "02"); + // 原交易分账模式(01:比例,02:金额) + bizContent.put("ori_division_mode", "02"); + + String result = YspayKit.divisionRequest(YspayKit.DIVISION_REFUND_URL, "ysepay.online.trade.refund.split", mchAppConfigContext.getMchApplyment().getIsvNo(), bizContent, null, payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + response = resJson.getJSONObject("ysepay_online_trade_refund_split_response"); + code = response.getString("code"); + }else { + String method = "ysepay.online.trade.refund"; + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment()); + if(RefundOrder.REFUND_ACCOUNT_PLAT.equals(refundOrder.getExtParam())){ + //一般户退款 + method = "ysepay.online.trade.refund.general.account"; + bizContent.put("refund_mer_id",isvParams.getPartnerId()); + } + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 退款金额 + bizContent.put("refund_amount", AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount())); + // 退款备注 + bizContent.put("refund_reason", refundOrder.getRefundReason()); + // 退款订单号 + bizContent.put("out_request_no", refundOrder.getRefundOrderId()); + String result = YspayKit.payRequest(method, mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + response = resJson.getJSONObject(method.replace(".","_") + "_response"); + code = response.getString("code"); + } + + if (YspayKit.RES_CODE.equals(code)) { + String transNo = response.getString("refundsn"); + channelRetMsg.setChannelOrderId(transNo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + } else { //其他状态, 表示支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + return channelRetMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + YspayIsvsubMchParams mchParams = (YspayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getMchApplyment().getAutoConfigMchAppId(), refundOrder.getIfCode()); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + + JSONObject bizContent = new JSONObject(); + + // 商户订单号 + bizContent.put("out_trade_no", refundOrder.getPayOrderId()); + // 退款订单号 + bizContent.put("out_request_no", refundOrder.getRefundOrderId()); + + String result = null; + // 如果为分账模式下单。走分账退款 + if (mchParams.getPayType() != null && mchParams.getPayType().equals(YspayIsvsubMchParams.PAY_TYPE_DIVISION)) { + result = YspayKit.payRequest(YspayKit.DIVISION_REFUND_URL,"ysepay.online.trade.refund.query", mchAppConfigContext, bizContent, getNotifyUrl(), refundOrder.getIfCode()); + }else { + result = YspayKit.payRequest("ysepay.online.trade.refund.query", mchAppConfigContext, bizContent, getNotifyUrl(), refundOrder.getIfCode()); + } + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_trade_refund_query_response"); + String code = response.getString("code"); + if (YspayKit.RES_CODE.equals(code)) { + String tradeStatus = response.getString("refund_state"); + if("success".equals(tradeStatus)){ // 退款成功 + String transNo = response.getString("refundsn"); + channelRetMsg.setChannelOrderId(transNo); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + + }else if ("fail".equals(tradeStatus)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + }else { //其他状态, 表示支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + return channelRetMsg; + } + + /** + * 银盛支持 + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + ChannelRefundLimit channelRefundLimit = new ChannelRefundLimit(true,true); + if(CS.SETTLEMENT_TYPE.D0.equals(settleType)){ + channelRefundLimit.setIsDefaultAccount(false); + } + return channelRefundLimit; + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + super.checkPlatAccount(refundOrder); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/exception/YsConfigException.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/exception/YsConfigException.java new file mode 100644 index 0000000..0e87c6c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/exception/YsConfigException.java @@ -0,0 +1,8 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.exception; + +public class YsConfigException extends RuntimeException { + + public YsConfigException(String text) { + super(text); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqEntity.java new file mode 100644 index 0000000..1718e2f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqEntity.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.model; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; +import java.util.Date; + +@Setter +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReqEntity implements Serializable { + + private String timeStamp; + + private String method; + + private String charset = "utf-8"; + + private String sign; + + private String check; + + private String bizContent; + + private String reqId; + + private String certId = "826521773920170"; + + private String version = "1.1"; + + public static ReqEntity get(ReqMethod.Method reqMethod) { + Date date = new Date(); + ReqEntity entity = new ReqEntity(); + entity.timeStamp = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"); + entity.method = reqMethod.getMethod(); + entity.reqId = "SYB_" + RandomUtil.randomString(4) + DateUtil.format(date, "yyMMddHHmmss"); + entity.setVersion(reqMethod.getVersion()); + return entity; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqMethod.java new file mode 100644 index 0000000..546237f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/ReqMethod.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2023/12/1 18:26 + */ +@Data +public class ReqMethod { + + private static final String DOMAIN = "https://ysgate.ysepay.com/openapi/"; + + private static final String DEFAULT_VERSION = "1.0"; + + private static final String VERSION_1_1 = "1.1"; + + private static final String VERSION_1_2 = "1.2"; + + private static final String VERSION_1_3 = "1.3"; + + @Getter + @AllArgsConstructor + public enum Method { + + ADD_CUST_INFO_APPLY("t1/smsc/addCustInfoApply", VERSION_1_1, "进件资料上送"), + MODIFY_CUST_INFO_APPLY("smsc/modifyCustInfoApply", VERSION_1_1, "未进件成功时资料修改"), + SETTLE_INFO_QUERY("pregate/settle/progressNotOrg", VERSION_1_1, "结算进度查询(只支持结算周期为T1和D1的结算进度查询)"), + UPLOAD("FILE/SMSC/UPLOAD", DEFAULT_VERSION, "进件图片上传"), + AUDIT_CUST_INFO_APPLY("t1/smsc/auditCustInfoApply", VERSION_1_1, "资料确认初审"), + QUERY_CUST_APPLY("smsc/queryCustApply", VERSION_1_1, "查询进件状态"), + SIGN("t1/smsc/sign", VERSION_1_1, "合同签约申请"), + SEND_SMS_OR_EMAIL_MSG("smsc/sign/sendSmsOrEmailMsg", DEFAULT_VERSION, "签约短信重发"), + QUERY_AUTH_INFO("smsc/saas/constract/queryAuthInfo", VERSION_1_1, "签约状态查询"), + QUERY_CONTRACT("smsc/sign/queryContract", DEFAULT_VERSION, "电子合同状态查询"), + SWEEP_REPORT("smsc/saas/sweep/sweepreport", DEFAULT_VERSION, "渠道报备"), + CHANGE_MERC_BASE_INFO("smsc/changeMercBaseInfo", VERSION_1_3, "基本信息变更"), + UPLOAD_CHANGE_PIC("file/smsc/uploadChangePic", DEFAULT_VERSION, "商户信息变更图片上传"), + QUERY_CUST_CHANGE("smsc/queryCustChange", VERSION_1_2, "变更状态查询"), + CHANGE_MERC_STL_ACC_INFO("t1/smsc/changeMercStlAccInfo", VERSION_1_3, "结算信息变更"), + CHANGE_RATE("smsc/changeRate", VERSION_1_3, "费率变更"), + OPEN_ONLINE_PAY("smsc/saas/authority/online", DEFAULT_VERSION, "开通/关闭线上D0权限"), + REGION_LIST("pregate/trade/findCmmtAreaInfoList", DEFAULT_VERSION, "地区信息查询"), + + ALI_PAY_GET_AUTH_STATE("pregate/alipay/getAuthState", DEFAULT_VERSION, "支付宝授权状态查询"), + WX_PAY_GET_AUTH_STATE("trade/scan/wechat/auth/getAuthState", DEFAULT_VERSION, "微信授权状态查询"), + GET_REPORT_INFO("report/scan/union/repAndAppIdQry", DEFAULT_VERSION, "查询报备信息"), + + APPID_ADD_OR_UPDATE("report.scan.union.appIdAddOrUpdate", DEFAULT_VERSION, "新增/修改appid"), + + AUTH_PATH_ADD("report.scan.union.authPathAdd", DEFAULT_VERSION, "新增/修改appid"), + + QUERY_SETTLE("pregate.settle.progressNotOrg", DEFAULT_VERSION, "新增/修改appid"), + + /** + * 查询银盛D0分账 + */ + QUERY_D0_DIVISION_SETTLE("trade.division.immediately.settleProgrQry", DEFAULT_VERSION, "查询银盛D0分账"), + ; + + private final String method; + + private final String version; + + private final String desc; + + public String getVersion() { + if (StringUtils.isEmpty(this.version)) { + return DEFAULT_VERSION; + } + return version; + } + } + + /** + * 获取请求接口地址 + * + * @param method + * @return + */ + public static String getUrl(Method method) { + return DOMAIN + method.getMethod().replace(".", "/"); + } + + /** + * 获取返回参数的最外层key + * + * @param method + * @return + */ + public static String getResponseKey(Method method) { + return method.getMethod().replace(".", "_") + "_response"; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/RespEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/RespEntity.java new file mode 100644 index 0000000..83071fe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/RespEntity.java @@ -0,0 +1,52 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.model; + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +@Setter +@Getter +public class RespEntity implements Serializable { + + /** + * 网关响应码 + */ + private String code; + + /** + * 网关响应码描述 + */ + private String msg; + + /** + * 业务响应码 + */ + private String subCode; + + /** + * 业务响应描述 + */ + private String subMsg; + + /** + * yyyy-MM-dd HH:mm:ss + */ + private String timeStamp; + + /** + * 随机参数 + */ + private String norce; + + /** + * 签名串 + */ + private String sign; + + /** + * 业务响应参数集合, + * 加密后的数据 + */ + private String businessData; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/YsCardType.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/YsCardType.java new file mode 100644 index 0000000..811045e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/model/YsCardType.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * TODO + * 卡类型 + * @author crystal + * @date 2023/12/8 17:57 + */ +@Getter +@AllArgsConstructor +public enum YsCardType { + + CREDIT("credit"), + + DEBIT("debit"); + + private String type; + + public static YsCardType getVal(String type){ + YsCardType[] values = values(); + for (YsCardType val:values) { + if(val.getType().equals(type)){ + return val; + } + } + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliBar.java new file mode 100644 index 0000000..26f5fd2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliBar.java @@ -0,0 +1,128 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliBarOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 支付宝 条码支付 + * + * @author xiaoyu + * + * @date 2022/7/8 11:24 + */ +@Service("yspayPaymentByAliBarService") //Service Name需保持全局唯一性 +public class AliBar extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliBarOrderRQ bizRQ = (AliBarOrderRQ) rq; + AliBarOrderRS res = ApiResBuilder.buildSuccess(AliBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "2", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 支付授权码 + bizContent.put("auth_code", bizRQ.getAuthCode()); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "1903000"); + // 支付场景 + bizContent.put("scene", "bar_code"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.barcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_barcodepay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.TRADE_SUCCESS.equals(tradeStatus)){ // 支付成功 + + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + // 卡类型 + String cardType = response.getString("card_type"); + YsCardType val = YsCardType.getVal(cardType); + String drType = CS.DrType.OTHER.getType(); + if(val != null){ + switch (val){ + case CREDIT: + drType = CS.DrType.CREDIT.getType(); + break; + case DEBIT: + drType = CS.DrType.DEBIT.getType(); + break; + } + } + channelRetMsg.setDrType(drType); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + }else { //其他状态, 表示支付中 + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + + res.setChannelRetMsg(channelRetMsg); + return res; + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliJsapi.java new file mode 100644 index 0000000..2487236 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliJsapi.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 支付宝 jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:20 + */ +@Service("yspayPaymentByAliJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 买家支付宝用户ID + bizContent.put("buyer_id", bizRQ.getBuyerUserId()); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.alijsapi.pay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_alijsapi_pay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + + String channelOrderNo = response.getString("trade_no"); + JSONObject payInfo = response.getJSONObject("jsapi_pay_info"); + String tradeNo = payInfo.getString("tradeNO"); + //付款信息 + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + res.setAlipayTradeNo(tradeNo); + res.setPayData(JSONObject.toJSONString(new ChannelJsapiMsg(tradeNo))); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliLite.java new file mode 100644 index 0000000..cfff393 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliLite.java @@ -0,0 +1,107 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 支付宝 小程序 + * + * @author xiaoyu + * + * @date 2022/4/13 18:30 + */ +@Service("yspayPaymentByAliLiteService") //Service Name需保持全局唯一性 +public class AliLite extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + try { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 买家支付宝用户ID + bizContent.put("buyer_id", bizRQ.getBuyerUserId()); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.alijsapi.pay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_alijsapi_pay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + + String channelOrderNo = response.getString("trade_no"); + JSONObject payInfo = response.getJSONObject("jsapi_pay_info"); + String tradeNo = payInfo.getString("tradeNO"); + //付款信息 + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + res.setAlipayTradeNo(tradeNo); + res.setPayData(JSONObject.toJSONString(new ChannelJsapiMsg(tradeNo))); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + throw ChannelException.sysError(response.getString("sub_msg")); +// channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); +// channelRetMsg.setChannelErrCode(response.getString("code")); +// channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliQr.java new file mode 100644 index 0000000..9d126b5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/AliQr.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +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.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliQrOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/** + * 银盛 支付宝扫码 + * + * @author xiaoyu + * + * @date 2022/5/24 17:38 + */ +@Service("yspayPaymentByAliQrService") //Service Name需保持全局唯一性 +public class AliQr extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + AliQrOrderRQ aliQrOrderRQ = (AliQrOrderRQ)rq; + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "1903000"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.qrcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_qrcodepay_response"); + String code = response.getString("code"); + + // 构造函数响应数据 + AliQrOrderRS res = ApiResBuilder.buildSuccess(AliQrOrderRS.class); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + + String transNo = response.getString("trade_no"); + String qrCdLink = response.getString("source_qr_code_url"); + channelRetMsg.setChannelOrderId(transNo); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(aliQrOrderRQ.getPayDataType())){ //二维码地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + }else{ //默认都为跳转地址方式 + res.setCodeUrl(qrCdLink); + jsapiMsg.setQrCodeUrl(qrCdLink); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpBar.java new file mode 100644 index 0000000..fc9c17a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpBar.java @@ -0,0 +1,129 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpBarOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 银盛 银联付款码(云闪付) + * + * @author jmdhappy + * + * @date 2022/3/17 11:11 + */ +@Service("yspayPaymentByUpBarService") //Service Name需保持全局唯一性 +public class UpBar extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + UpBarOrderRQ bizRQ = (UpBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + UpBarOrderRQ bizRQ = (UpBarOrderRQ) rq; + UpBarOrderRS res = ApiResBuilder.buildSuccess(UpBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "2", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 支付授权码 + bizContent.put("auth_code", bizRQ.getAuthCode()); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "9001002"); + + // 渠道终端号 20220429 添加 + String channelTrmNo = queryStoreTerminalChannelTrmNo(rq.getMchTrmNo(), payOrder); + if(StringUtils.isNotEmpty(channelTrmNo)){ + bizContent.put("device_info", channelTrmNo); // 终端设备编号 + } + // 支付场景 + bizContent.put("scene", "bar_code"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.barcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_barcodepay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.TRADE_SUCCESS.equals(tradeStatus)){ // 支付成功 + + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + // 卡类型 + String cardType = response.getString("card_type"); + YsCardType val = YsCardType.getVal(cardType); + String drType = CS.DrType.OTHER.getType(); + if(val != null){ + switch (val){ + case CREDIT: + drType = CS.DrType.CREDIT.getType(); + break; + case DEBIT: + drType = CS.DrType.DEBIT.getType(); + break; + } + } + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + }else { //其他状态, 表示支付中 + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpQr.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpQr.java new file mode 100644 index 0000000..5605603 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/UpQr.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.UpQrOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 银联扫码支付 + * + * @author zx + * + * @date 2022/06/22 20:09 + */ +@Service("yspayPaymentByUpQrService") //Service Name需保持全局唯一性 +@Slf4j +public class UpQr extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + + UpQrOrderRQ bizRQ = (UpQrOrderRQ)rq; + + // 构造函数响应数据 + UpQrOrderRS res = ApiResBuilder.buildSuccess(UpQrOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + try { + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "9001002"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.qrcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_qrcodepay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + + String transNo = response.getString("trade_no"); + String qrCdLink = response.getString("source_qr_code_url"); + channelRetMsg.setChannelOrderId(transNo); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + if(CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码地址 + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + jsapiMsg.setQrCodeUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(qrCdLink)); + }else{ //默认都为跳转地址方式 + res.setCodeUrl(qrCdLink); + jsapiMsg.setQrCodeUrl(qrCdLink); + } + res.setPayData(JSON.toJSONString(jsapiMsg)); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + return res; + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + return res; + } + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } catch (ChannelException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return res; + } catch (Exception e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg("系统异常"); + return res; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxBar.java new file mode 100644 index 0000000..a6b2cee --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxBar.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxBarOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛 微信 条码支付 + * + * @author xiaoyu + * + * @date 2022/3/10 10:04 + */ +@Slf4j +@Service("yspayPaymentByWxBarService") //Service Name需保持全局唯一性 +public class WxBar extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + WxBarOrderRQ bizRQ = (WxBarOrderRQ) rq; + WxBarOrderRS res = ApiResBuilder.buildSuccess(WxBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "2", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 支付授权码 + bizContent.put("auth_code", bizRQ.getAuthCode()); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "1902000"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.barcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_barcodepay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.TRADE_SUCCESS.equals(tradeStatus)){ // 支付成功 + + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + // 卡类型 + String cardType = response.getString("card_type"); + YsCardType val = YsCardType.getVal(cardType); + String drType = CS.DrType.OTHER.getType(); + if(val != null){ + switch (val){ + case CREDIT: + drType = CS.DrType.CREDIT.getType(); + break; + case DEBIT: + drType = CS.DrType.DEBIT.getType(); + break; + } + } + channelRetMsg.setDrType(drType); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + }else { //其他状态, 表示支付中 + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + + res.setChannelRetMsg(channelRetMsg); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxJsapi.java new file mode 100644 index 0000000..6af1d2c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxJsapi.java @@ -0,0 +1,122 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxJsapiOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/4/15 15:37 + */ +@Slf4j +@Service("yspayPaymentByWxJsapiService") //Service Name需保持全局唯一性 +public class WxJsapi extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxJsapiOrderRS res = ApiResBuilder.buildSuccess(WxJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 商户号 + // 设置请求参数 + WxJsapiOrderRQ bizRQ = (WxJsapiOrderRQ) rq; + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 用户在商户appid下的唯一标识 + bizContent.put("sub_openid", bizRQ.getChannelUserId()); + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + // 商户appId + bizContent.put("appid", bizRQ.getSubAppid()); + }else { + // 商户appId + bizContent.put("appid", oauth2Params.getAppId()); + } + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.weixin.pay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_weixin_pay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + // 转换为微信接收参数 + String tradeNo = response.getString("trade_no"); + JSONObject payInfo = response.getJSONObject("jsapi_pay_info"); + channelRetMsg.setChannelOrderId(tradeNo); + res.setPayInfo(payInfo.toJSONString()); + res.setPayData(payInfo.toJSONString()); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + throw ChannelException.sysError(response.getString("sub_msg")); + } + }catch (BizException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg(e.getMessage()); + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxLite.java new file mode 100644 index 0000000..370644f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/WxLite.java @@ -0,0 +1,136 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.WxLiteOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银盛支付 微信jsapi + * + * @author xiaoyu + * + * @date 2022/6/13 17:52 + */ +@Slf4j +@Service("yspayPaymentByWxLiteService") //Service Name需保持全局唯一性 +public class WxLite extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getOpenid())){ + throw new BizException("[openId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + WxLiteOrderRS res = ApiResBuilder.buildSuccess(WxLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + try { + // 设置请求参数 + WxLiteOrderRQ bizRQ = (WxLiteOrderRQ) rq; + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + // 商户号 + // 设置请求参数 + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 用户在商户appid下的唯一标识 + bizContent.put("sub_openid", bizRQ.getChannelUserId()); + + bizContent.put("is_minipg", "1"); + + // 接口上传的appId + if (StringUtils.isNotEmpty(bizRQ.getSubAppid())) { + // 商户appId + bizContent.put("appid", bizRQ.getSubAppid()); + }else { + // 商户appId + bizContent.put("appid", oauth2Params.getLiteAppId()); + } + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.weixin.pay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_weixin_pay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + // 转换为微信接收参数 + String tradeNo = response.getString("trade_no"); + JSONObject payInfo = response.getJSONObject("jsapi_pay_info"); + channelRetMsg.setChannelOrderId(tradeNo); + res.setPayInfo(payInfo.toJSONString()); + res.setPayData(payInfo.toJSONString()); + + ChannelJsapiMsg channelJsapiMsg = new ChannelJsapiMsg(); + res.getChannelRetMsg().setJsapiMsg(channelJsapiMsg); + channelJsapiMsg.setAppId(payInfo.getString("appId")); + channelJsapiMsg.setNonceStr(payInfo.getString("nonceStr")); + channelJsapiMsg.setPayPackage(payInfo.getString("package")); + channelJsapiMsg.setPaySign(payInfo.getString("paySign")); + channelJsapiMsg.setTimeStamp(payInfo.getString("timeStamp")); + + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + throw ChannelException.sysError(response.getString("sub_msg")); + } + }catch (BizException e) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrMsg(e.getMessage()); + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfBar.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfBar.java new file mode 100644 index 0000000..2d7fee6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfBar.java @@ -0,0 +1,133 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfBarOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.YsCardType; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 云闪付条码支付 + * + * @author xiaoyu + * + * @date 2022/10/13 9:17 + */ +@Service("yspayPaymentByYsfBarService") //Service Name需保持全局唯一性 +public class YsfBar extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getAuthCode())){ + throw new BizException("用户支付条码[authCode]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + String logPrefix = "【云闪付条码(unionpay)支付】"; + + YsfBarOrderRQ bizRQ = (YsfBarOrderRQ) rq; + YsfBarOrderRS res = ApiResBuilder.buildSuccess(YsfBarOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "2", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 支付授权码 + bizContent.put("auth_code", bizRQ.getAuthCode()); + // 二维码行别 微信-1902000 ,支付宝-1903000,中国银联-9001002,招商银行:-3085840 + bizContent.put("bank_type", "9001002"); + + // 渠道终端号 20220429 添加 + String channelTrmNo = queryStoreTerminalChannelTrmNo(rq.getMchTrmNo(), payOrder); + if(StringUtils.isNotEmpty(channelTrmNo)){ + bizContent.put("device_info", channelTrmNo); // 终端设备编号 + } + // 支付场景 + bizContent.put("scene", "bar_code"); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.barcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_barcodepay_response"); + String code = response.getString("code"); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.TRADE_SUCCESS.equals(tradeStatus)){ // 支付成功 + + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 支付中 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + // 卡类型 + String cardType = response.getString("card_type"); + YsCardType val = YsCardType.getVal(cardType); + String drType = CS.DrType.OTHER.getType(); + if(val != null){ + switch (val){ + case CREDIT: + drType = CS.DrType.CREDIT.getType(); + break; + case DEBIT: + drType = CS.DrType.DEBIT.getType(); + break; + } + } + channelRetMsg.setDrType(drType); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + }else { //其他状态, 表示支付中 + String transNo = response.getString("trade_no"); + channelRetMsg.setChannelOrderId(transNo); + // 开启轮询查单 + channelRetMsg.setNeedQuery(true); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfJsapi.java new file mode 100644 index 0000000..a1f0d60 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/payway/YsfJsapi.java @@ -0,0 +1,113 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.YsfJsapiOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.YspayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 银联jsapi + * + * @author xiaoyu + * + * @date 2022/10/13 9:17 + */ +@Service("yspayPaymentByYsfJsapiService") //Service Name需保持全局唯一性 +public class YsfJsapi extends YspayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getUserId())){ + throw new BizException("[userId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + YsfJsapiOrderRS res = ApiResBuilder.buildSuccess(YsfJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + YsfJsapiOrderRQ bizRQ = (YsfJsapiOrderRQ) rq; + try { + JSONObject bizContent = new JSONObject(); + // 默认支付参数 + YspayKit.setPayParams(mchAppConfigContext, bizContent, "1", payOrder.getIfCode()); + + // 商户订单号 + bizContent.put("out_trade_no", payOrder.getPayOrderId()); + // 订单交易日期 + bizContent.put("shopdate", DateUtil.format(payOrder.getCreatedAt(), DatePattern.PURE_DATE_PATTERN)); + // 订单备注 + bizContent.put("subject", payOrder.getSubject()); + // 金额 元 + bizContent.put("total_amount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + // 买家支付宝用户ID + bizContent.put("userId", bizRQ.getUserId()); + // 是否允许多次支付,Y:允许;N:不允许 + bizContent.put("allow_repeat_pay", "Y"); + // 行别 9001002 银联 + bizContent.put("bank_type", "9001002"); + // IP地址 + bizContent.put("spbill_create_ip", payOrder.getClientIp()); + // 交易结束时间 + String expiredTime = DateUtil.formatBetween(DateUtil.between(payOrder.getCreatedAt(), payOrder.getExpiredTime(), DateUnit.MINUTE)).replace("毫秒", ""); + bizContent.put("timeout_express", expiredTime+"m"); + + String result = YspayKit.payRequest("ysepay.online.cupmulapp.qrcodepay", mchAppConfigContext, bizContent, getNotifyUrl(), payOrder.getIfCode()); + JSONObject resJson = JSONObject.parseObject(result); + JSONObject response = resJson.getJSONObject("ysepay_online_cupmulapp_qrcodepay_response"); + String code = response.getString("code"); + channelRetMsg.setChannelBizData(response); + if (YspayKit.RES_CODE.equals(code)) { + // 分账登记接口调用 + payOrderDivision(mchAppConfigContext, payOrder); + + String tradeStatus = response.getString("trade_status"); + if(YspayKit.WAIT_BUYER_PAY.equals(tradeStatus)){ // 交易中 + String channelOrderNo = response.getString("trade_no"); + String url = response.getString("web_url"); + // 付款信息 + channelRetMsg.setChannelOrderId(channelOrderNo); + // 获取payInfo + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + jsapiMsg.setRedirectUrl(url); + res.setRedirectUrl(url); + res.setPayData(JSON.toJSONString(jsapiMsg)); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else if (YspayKit.TRADE_FAILED.equals(tradeStatus)){ // 失败 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(response.getString("code")); + channelRetMsg.setChannelErrMsg(response.getString("sub_msg")); + } + }catch (Exception e) { + throw ChannelException.sysError(e.getMessage()); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/AESUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/AESUtil.java new file mode 100644 index 0000000..2f55321 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/AESUtil.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.AES; +import com.jeequan.jeepay.core.exception.BizException; + +import java.nio.charset.StandardCharsets; + +public class AESUtil { + + /** + * 加密 + * + * @param content 需要加密的内容 + * @param password 加密密钥 + */ + public static byte[] encrypt(byte[] content, byte[] password) { + AES aes = SecureUtil.aes(password); + return aes.encrypt(content); + } + + + /**解密 + * @param content 待解密内容 + * @param password 解密密钥 + */ + public static byte[] decrypt(byte[] content, byte[] password) { + AES aes = SecureUtil.aes(password); + return aes.decrypt(content); + } + + + public static void main(String[] args) { + + try { + String content = "IgVXDyReWEj4qOEtoVWf7K36a+SpRe8zmbRbouki/kcJGSoRYqmhznvA7nF86DEIfB+XYUX6vLRyMP\n" + + "4CoqPiWHGW3WOquAUF1QlEH6ZR9HqDEucT65lqhMzAmk6Sxv6TRLySWjffjmN0VS1iIfyNF5+jR9L\n" + + "mFjrY6neoEErUHjlsyZBqLlDDtYFy4hlLSGTfFLNnus/WfDaAmevq7tBwlJUBkRX2MU9FlQ2YzOHpQ36\n" + + "9mNOAspbIiWgA5MQXlCqjdiOq22q653udLhfwOhA3+TKUEju4pS05EYG3JQtmN8aMQtCj6xJCQPP\n" + + "/YAp+AIpJ1dqIAdqvoSKGUQEWYLNaGJsnBrq2yS/PeyNYGBSzic5QTb+nsZVrUB+wLp68qjZUtqr/cvc\n" + + "pwB1I4kKHrfS45SCkJ8PtSeIUHdOE+m+F2sSET2KBB2nQHsIEy/IVJ1xXI2LDgPhBtnQWLirt6jzIOFy5x\n" + + "XltaUou5hp0NPmMR+LzyFYB86QN3v7Hcr4rt0zVN/aoBo2BuSWu5cFkiBJrOPu34N5VSZRznqL/asO\n" + + "SqgLxWlVKiGyZnrJp/HqLQ5QD"; + + String password = "0123456789abcdef"; + System.out.println(decryptStrAES(content, password)); + }catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static String decryptStrAES(String text, String key){ + AES aes = SecureUtil.aes(key.getBytes(StandardCharsets.UTF_8)); + return aes.decryptStr(text, StandardCharsets.UTF_8); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ApplymentNotify.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ApplymentNotify.java new file mode 100644 index 0000000..39d4754 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ApplymentNotify.java @@ -0,0 +1,128 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Setter +@Getter +public class ApplymentNotify { + + /** + * 商户资料确认回调 + */ + public static final String TYPE_MCH_APPLY = "1"; + + /** + * 签约回调 + */ + public static final String TYPE_MCH_SIGN = "2"; + + /** + * 商户资料变更回调 + */ + public static final String TYPE_MCH_CHANGE = "3"; + + /** + * 费率变更 + */ + public static final String TYPE_MCH_RATE_CHANGE = "5"; + + /** + * 报备 + */ + public static final String TYPE_MCH_REPORT = "6"; + + + private String notifyType; + + private String status; + + private Cust cust; + + private Change change; + + private Auth auth; + + private Report report; + + @Setter + @Getter + public static class Cust { + + private String sysFlowId; + + private String note; + + private String custId; + + private String status; + + private String mercNm; + + private String mercShortNm; + + } + + @Setter + @Getter + public static class Change { + + private String changeSysFlowId; + + private String note; + + private String status; + } + + @Setter + @Getter + public static class Auth { + + private String authId; + + private String mercId; + + private String note; + + private String signId; + + private String status; + } + + @Setter + @Getter + public static class Report { + + private String authId; + + private String mercId; + + private String status; + + private List thridMercList; + } + + @Setter + @Getter + public static class ThirdMerc { + + private String apprSts; + + private String mercId; + + private String thridMercId; + + /** + * 备注 + */ + private String remark; + + /** + * 报备渠道 NUCC_WECHAT:微信支付(网联)、CUPS_WECHAT:微信支付(银联总部)、CUPS_ALIPAY:支付宝(银联总部)、NUCC_ALIPAY:支付宝(网联) + */ + private String reportChannel; + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/BankInfoUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/BankInfoUtil.java new file mode 100644 index 0000000..590f6a0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/BankInfoUtil.java @@ -0,0 +1,228 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; + + +@Slf4j +public class BankInfoUtil { + + private static final String ALLCHAR = "0123456789ABCDEF"; + + /** + * 发起进件请求 + * @param isvParams + * @param bizContent + * @return + */ + public static JSONObject getBankInfoList(YspayIsvParams isvParams, JSONObject bizContent) { + + FileInputStream fileInputStream = null; + try { + + String reqUrl = "https://ysgate.ysepay.com/openapi/pregate/trade/findBankNameAndBankCode"; + + // 公共参数 + JSONObject reqParams = new JSONObject(); + //接口方法名,根据接口文档取值 + reqParams.put("method", "pregate.trade.findBankNameAndBankCode"); + // 版本号 + reqParams.put("version", "1.0"); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求流水 + reqParams.put("reqId", DateKit.currentTimeMillis()+""); + // 商户号 + reqParams.put("certId", isvParams.getPartnerId()); + // 请求时间 + reqParams.put("timeStamp", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)); + + /** 2、生成对业务参数加密的密钥*/ + StringBuilder sb = new StringBuilder(); + SecureRandom random = RandomUtil.getSecureRandom(); + for (int i = 0; i < 16; i++) { + sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); + } + String key = toHexString(sb.toString()); + // 证书地址 + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + + String check = null; + if ("RSA".equals(isvParams.getSignType())) { + fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile())); + byte[] byte1 = encrypt(fileInputStream, hexStringToBytes(key)); + //加密后的密钥 + check = Base64.encodeBase64String(byte1); + + }else if ("SM".equals(isvParams.getSignType())){ + String filePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + check = GMSignUtils.encryptData(filePath, key); + }else { + log.error("未识别的签名类型"); + } + + byte[] bte= encrypt(JSON.toJSONBytes(bizContent, SerializerFeature.WriteNullStringAsEmpty), hexStringToBytes(key)); + String msgBizContent = Base64.encodeBase64String(bte); + + reqParams.put("check", check); + reqParams.put("bizContent", msgBizContent); + + // 生成签名 + String sign = YspayKit.getSign(isvParams, reqParams); + reqParams.put("sign", sign); + // 发起请求 + log.info("【银盛进件】请求地址:{},发起请求:{}", reqUrl, reqParams); + String response = HttpRequest.post(reqUrl) + .header("Content-type", "application/x-www-form-urlencoded") + .timeout(20000) + .charset(StandardCharsets.UTF_8.name()) + .body(reqParams.toJSONString()) + .execute().body(); + byte[] res = Base64.decodeBase64(response); + JSONObject parse = (JSONObject) JSON.parse(new String(res, StandardCharsets.UTF_8)); + log.info("【银盛进件】响应结果:{}, 响应结果参数:{}", response, parse); + JSONObject bankCodeListJson = null; + if (!"00000".equals(parse.getString("code")) || !"0000".equals(parse.getString("subCode"))) { + return bankCodeListJson; + } + /** 10、使用上面生成的加密密钥key,解密返回的业务参数*/ + if(StringUtils.isNotBlank(parse.getString("businessData"))) { + byte[] data_ = Base64.decodeBase64(parse.getString("businessData")); + byte[] data = decrypt(data_, hexStringToBytes(key)); + bankCodeListJson = JSON.parseObject(new String(data, StandardCharsets.UTF_8)); + log.info("【银盛进件】解密后的完整参数为:{}", bankCodeListJson); + } + return bankCodeListJson; + }catch (Exception e) { + throw new BizException(e.getMessage()); + }finally { + if(fileInputStream != null){ + try { + fileInputStream.close(); + } catch (IOException e) { + } + } + } + } + + // 转化字符串为十六进制编码 + public static String toHexString(String s) { + String str = ""; + for (int i = 0; i < s.length(); i++) { + int ch = s.charAt(i); + String s4 = Integer.toHexString(ch); + str = str + s4; + } + return str; + } + + public static byte[] hexStringToBytes(String hexString) { + if (hexString == null || hexString.isEmpty()) { + return null; + } + hexString = hexString.toUpperCase(); + int length = hexString.length() / 2; + char[] hexChars = hexString.toCharArray(); + byte[] d = new byte[length]; + for (int i = 0; i < length; i++) { + int pos = i * 2; + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]) & 0xff); + } + return d; + } + public static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } + + /** + * 从指定目录书路径获取Certificate对象 + * @return + */ + public static Certificate initValidateCertFromDir(FileInputStream fileInputStream) throws Exception { + CertificateFactory cf = null; + FileInputStream in = null; + Certificate validateCert = null; + try { + cf = CertificateFactory.getInstance("X.509"); + validateCert = cf.generateCertificate(fileInputStream); + } catch (CertificateException e) { + throw e; + } finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + throw e; + } + } + } + return validateCert; + } + + public static byte[] encrypt(FileInputStream fileInputStream, byte[] content) throws Exception{ + Cipher cipher=Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, initValidateCertFromDir(fileInputStream).getPublicKey()); + return cipher.doFinal(content); + } + + /** + * 加密 + * + * @param content 需要加密的内容 + * @param password 加密密钥 + * @return + */ + public static byte[] encrypt(byte[] content, byte[] password) throws Exception { + try { + SecretKeySpec key = new SecretKeySpec(password,"AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(content); + return result; // 加密 + } catch (Exception e) { + throw e; + } + } + + /**解密 + * @param content 待解密内容 + * @param password 解密密钥 + * @return + * @throws Exception + */ + public static byte[] decrypt(byte[] content, byte[] password) throws Exception { + try { + SecretKeySpec key = new SecretKeySpec(password,"AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(content); + return result; // 解密 + } catch (Exception e) { + throw e; + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ByteUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ByteUtil.java new file mode 100644 index 0000000..91c5dd3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/ByteUtil.java @@ -0,0 +1,503 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import java.io.ByteArrayOutputStream; + + +public class ByteUtil { + + private static String hexStr = "0123456789ABCDEF"; + + private static final char[] BToA = "0123456789abcdef".toCharArray(); + + private static final String N_LINE = "----------------------------------------------------------------------------"; + /** + * 二进制 + */ + private static final int DECIMAL = 2; + + /** + * @param iSource + * @param iArrayLen + * @return + */ + public static byte[] int2ByteArray(int iSource, int iArrayLen) { + byte[] bLocalArr = new byte[iArrayLen]; + for (int i = iArrayLen; (i < 4) && (i > 0); i--) { + bLocalArr[i - 1] = (byte) (iSource >> 8 * (iArrayLen - i) & 0xFF); + } + return bLocalArr; + } + + public static String trace(byte[] inBytes) { + int i, j = 0; + byte[] temp = new byte[76]; + bytesSet(temp, ' '); + StringBuffer strc = new StringBuffer(""); + strc.append(N_LINE + "\n"); + for (i = 0; i < inBytes.length; i++) { + if (j == 0) { + System.arraycopy(String.format("%03d: ", i).getBytes(), 0, + temp, 0, 5); + System.arraycopy(String.format(":%03d", i + 15).getBytes(), 0, + temp, 72, 4); + } + System.arraycopy(String.format("%02X ", inBytes[i]).getBytes(), 0, + temp, j * 3 + 5 + (j > 7 ? 1 : 0), 3); + if (inBytes[i] == 0x00) { + temp[j + 55 + ((j > 7 ? 1 : 0))] = '.'; + } else { + temp[j + 55 + ((j > 7 ? 1 : 0))] = inBytes[i]; + } + j++; + if (j == 16) { + strc.append(new String(temp)).append("\n"); + bytesSet(temp, ' '); + j = 0; + } + } + if (j != 0) { + strc.append(new String(temp)).append("\n"); + bytesSet(temp, ' '); + } + strc.append(N_LINE + "\n"); + return strc.toString(); + } + + /** + * byte数组赋值 + * + * @param inBytes + * @param fill + * @return + * @throws Exception + */ + private static void bytesSet(byte[] inBytes, char fill) { + if (inBytes.length == 0) { + return; + } + for (int i = 0; i < inBytes.length; i++) { + inBytes[i] = (byte) fill; + } + } + + + public static byte[] byteAndByte(byte[] begin, byte[] second) { + if (begin == null || begin.length == 0) { + if (second != null && second.length != 0) { + return second; + } else { + return null; + } + } else if (second == null || second.length == 0) { + return begin; + } + byte[] newTotal = new byte[begin.length + second.length]; + for (int i = 0; i < begin.length; i++) { + newTotal[i] = begin[i]; + } + for (int i = begin.length; i < second.length + begin.length; i++) { + newTotal[i] = second[i - begin.length]; + } + return newTotal; + } + + + public static byte[] getsubByte(byte[] total, int begin, int length) { + if (length > 0) { + byte[] newTotal = new byte[length]; + for (int i = begin; i < length + begin; i++) { + newTotal[i - begin] = total[i]; + } + return newTotal; + } + return new byte[0]; + } + + public static String fillString(String string, char filler,int totalLength, boolean atEnd) { + byte[] tempbyte = string.getBytes(); + int currentLength = tempbyte.length; + int delta = totalLength - currentLength; + for (int i = 0; i < delta; i++) { + if (atEnd) { + string += filler; + } else { + string = filler + string; + } + } + return string; + } + + + public static byte[] hexStringToBytes(String hexString) { + if (hexString == null || hexString.equals("")) { + return null; + } + hexString = hexString.toUpperCase(); + int length = hexString.length() / 2; + char[] hexChars = hexString.toCharArray(); + byte[] d = new byte[length]; + for (int i = 0; i < length; i++) { + int pos = i * 2; + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]) & 0xff); + } + return d; + } + + public static byte charToByte(char c) { + return (byte) "0123456789ABCDEF".indexOf(c); + } + + public static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder(""); + if (src == null || src.length <= 0) { + return null; + } + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuilder.append(0); + } + stringBuilder.append(hv); + } + return stringBuilder.toString().toUpperCase(); + + } + + public static String bytesToString(byte[] src, int begin, int length) { + String str1 = null; + StringBuilder sb = new StringBuilder(""); + if (begin == 0 && length == 0) { + for (byte element : src) { + sb.append(String.valueOf(element)); + } + } else { + for (int i = begin; i < begin + length; i++) { + byte element = src[i]; + sb.append(String.valueOf(element)); + } + } + str1 = sb.toString(); + return str1; + + } + + /** + * @param bytes + * @return 将二进制转换为十六进制字符输出 + */ + public static String binaryToHexString(byte[] bytes) { + String result = ""; + String hex = ""; + for (int i = 0; i < bytes.length; i++) { + // 字节高4位 + hex = String.valueOf(hexStr.charAt((bytes[i] & 0xF0) >> 4)); + // 字节低4位 + hex += String.valueOf(hexStr.charAt(bytes[i] & 0x0F)); + result += hex; + } + return result.toUpperCase(); + } + + + + + /* + * 二进制数转换到十进制数 + */ + public static String binaryToDecimal(String binary) { + StringBuffer buf = new StringBuffer(); + String[] strBinary = binary.split(" ");// 根据空格拆分二进制数 + for (String str : strBinary) {// 提取二进制数 + StringBuffer strBuf = new StringBuffer(str); + char[] element = strBuf.reverse().toString().toCharArray();// 反转二进制数方便运算 + int digit = 0;// 次幕 + int result = 0;// 结果 + for (char temp : element) {// 提取单个数 + int intNumber = Integer.parseInt(Character.toString(temp)); + intNumber = intNumber * (int) (Math.pow(DECIMAL, digit));// 根据位数算结果 + // 算法:位数*2的次幕 + result = result + intNumber; + digit = digit + 1;// 次幕加一 + } + buf.append(result); + buf.append(" "); + } + return buf.toString(); + } + + /** + * 转化十六进制编码为字符串 + * 没有设置编码格式 + */ + public static String toStringHex(String s) { + byte[] baKeyword = new byte[s.length() / 2]; + for (int i = 0; i < baKeyword.length; i++) { + try { + baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring( + i * 2, i * 2 + 2), 16)); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + s = new String(baKeyword, "utf-8");// UTF-16le:Not + } catch (Exception e1) { + e1.printStackTrace(); + } + return s; + } + + /** + * 转化十六进制编码为字符串 + * 设置编码格式 + */ + public static String toStringHex(String s, String charset) { + byte[] baKeyword = new byte[s.length() / 2]; + for (int i = 0; i < baKeyword.length; i++) { + try { + baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring( + i * 2, i * 2 + 2), 16)); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + s = new String(baKeyword, charset); + } catch (Exception e1) { + e1.printStackTrace(); + } + return s; + } + + /** + * @函数功能: BCD码转为10进制串(阿拉伯数据) + * @输入参数: BCD码 + * @输入参数: format 补码方式 : true : 前补零 ; false : 后补零 + * @输入参数: length 原长度 + * @输出结果: 10进制串 + */ + public static String cbcd2string(byte[] bytes, boolean format, int length) { + StringBuffer temp = new StringBuffer(bytes.length * 2); + + for (int i = 0; i < bytes.length; i++) { + temp.append((byte) ((bytes[i] & 0xf0) >>> 4)); + temp.append((byte) (bytes[i] & 0x0f)); + } + + String val = temp.toString(); + // 左去零 + if (format) { + if (val.length() > length) { + return val.substring(0, 1).equalsIgnoreCase("0") ? val.substring(1) : val; + } else { + return val; + } + } + // 右去零 + else { + if (val.length() > length) { + return val.substring(val.length() - 1, val.length()).equalsIgnoreCase("0") ? val.substring(0, val.length() - 1) : val; + } else { + return val; + } + } + + } + + /** + * @函数功能: 10进制串转为BCD码 + * @输入参数: 10进制串 + * @输入参数: format 补码方式 : true : 前补零 ; false : 后补零 + * @输出结果: BCD码 + */ + public static byte[] str2cbcd(String asc, boolean format) { + int len = asc.length(); + int mod = len % 2; + + if (mod != 0) { + + if (format) { + asc = "0" + asc; + len = asc.length(); + } else { + asc = asc + "0"; + len = asc.length(); + } + } + + byte abt[] = new byte[len]; + if (len >= 2) { + len = len / 2; + } + + byte bbt[] = new byte[len]; + abt = asc.getBytes(); + int j, k; + + for (int p = 0; p < asc.length() / 2; p++) { + if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) { + j = abt[2 * p] - '0'; + } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) { + j = abt[2 * p] - 'a' + 0x0a; + } else { + j = abt[2 * p] - 'A' + 0x0a; + } + + if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) { + k = abt[2 * p + 1] - '0'; + } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) { + k = abt[2 * p + 1] - 'a' + 0x0a; + } else { + k = abt[2 * p + 1] - 'A' + 0x0a; + } + + int a = (j << 4) + k; + byte b = (byte) a; + bbt[p] = b; + } + return bbt; + } + + /** + * @函数功能: 16进制串转为BCD码 + * @输入参数: 16进制串 + * @输入参数: format 补码方式 : true : 前补零 ; false : 后补零 + * @输出结果: BCD码 + */ + public static byte[] str2Bcd(String s, boolean format) { + if (s.length() % 2 != 0) { + if (format) { + s = "0" + s; + + } else { + s = s + "0"; + } + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + char[] cs = s.toCharArray(); + for (int i = 0; i < cs.length; i += 2) { + int high = cs[i] - '0'; + if (high > 9) { + high = high - ('A' - '9' - 1); + } + int low = cs[i + 1] - '0'; + if (low > 9) { + low = low - ('A' - '9' - 1); + } + + baos.write(high << 4 | low); + } + return baos.toByteArray(); + } + + /** + * @函数功能: BCD码转为十六进制串 + * @输入参数: BCD码 + * @输入参数: format 补码方式 : true : 前补零 ; false : 后补零 + * @输入参数: length 原长度 + * @输出结果: 10进制串 + */ + public static String bcd2Str(byte[] b, boolean format, int length) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < b.length; i++) { + + int h = ((b[i] & 0xff) >> 4) + '0'; + if (h > '9') { + h = h + ('A' - '9' - 1); + } + sb.append((char) h); + int l = (b[i] & 0x0f) + '0'; + + if (l > '9') { + l = l + ('A' - '9' - 1); + } + sb.append((char) l); + } + + String val = sb.toString().toUpperCase(); + // 左去零 + if (format) { + if (val.length() > length) { + return val.substring(0, 1).equalsIgnoreCase("0") ? val.substring(1) : val; + } else { + return val; + } + } + // 右去零 + else { + if (val.length() > length) { + return val.substring(val.length() - 1, val.length()).equalsIgnoreCase("0") ? val.substring(0, val.length() - 1) : val; + } else { + return val; + } + } + } + + /** + * @函数功能: BCD码转ASC码 + * @输入参数: BCD串 + * @输出结果: ASC码 + */ + public static String bcd2ASC(byte[] bytes) { + StringBuffer temp = new StringBuffer(bytes.length * 2); + + for (int i = 0; i < bytes.length; i++) { + int h = ((bytes[i] & 0xf0) >>> 4); + int l = (bytes[i] & 0x0f); + temp.append(BToA[h]).append(BToA[l]); + } + return temp.toString().toUpperCase(); + } + + + // 转化字符串为十六进制编码 + public static String toHexString(String s) { + String str = ""; + for (int i = 0; i < s.length(); i++) { + int ch = s.charAt(i); + String s4 = Integer.toHexString(ch); + str = str + s4; + } + return str; + } + + public static byte[] byteTobyte(byte[] data, int index, int lenth) { + byte[] b = new byte[lenth]; + for (int i = index; i < index + lenth; i++) { + b[i - index] = data[i]; + } + return b; + } + + public static byte[] replenishByteTo8(byte[] b) { + int i = b.length; + int x = i % 8; + if (x != 0) { + x = 8 - x; + String replenish = ""; + for (int j = 0; j < x; j++) { + replenish += "FF"; + } + return byteAndByte(b, hexStringToBytes(replenish)); + } else { + return b; + } + } + + public static byte[] replenishByteTo16(byte[] b) { + int i = b.length; + int x = i % 16; + if (x != 0) { + x = 16 - x; + String replenish = ""; + for (int j = 0; j < x; j++) { + replenish += "FF"; + } + return byteAndByte(b, hexStringToBytes(replenish)); + } else { + return b; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/CertUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/CertUtil.java new file mode 100644 index 0000000..03d2a07 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/CertUtil.java @@ -0,0 +1,212 @@ +/** + * + * Licensed Property to China UnionPay Co., Ltd. + * + * (C) Copyright of China UnionPay Co., Ltd. 2010 + * All Rights Reserved. + * + * + * Modification History: + * ============================================================================= + * Author Date Description + * ------------ ---------- --------------------------------------------------- + * xshu 2014-05-28 证书工具类. + * ============================================================================= + */package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cfca.sadk.org.bouncycastle.util.encoders.Base64Kit; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Enumeration; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CertUtil { + /** 证书容器. */ + private static KeyStore keyStore = null; + + /** 验证签名证书. */ + private static Certificate validateCert = null; + + /** 验证签名证书. KEYSTORE_TYPE-PKCS12 */ + private static final String KEYSTORE_TYPE = "PKCS12"; + + /** 验证签名证书. CERTFACTORY_TYPE-PKCS12 */ + private static final String CERTFACTORY_TYPE= "X.509"; + + /** + * 加载签名证书 + */ + public static KeyStore initSignCert(String pfxPath,String pfxPwd) throws Exception { + if (null != keyStore) { + keyStore = null; + } + try { + // 默认存放的文件夹路径 + keyStore = getKeyInfo(pfxPath,pfxPwd, KEYSTORE_TYPE); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + return keyStore; + } + /** + * 将证书文件读取为证书存储对象 + * + * @param pfxkeyfile + * 证书文件名 + * @param keypwd + * 证书密码 + * @param type + * 证书类型 ,以.pfx结尾用PKCS12 + * @return 证书对象 + * @throws IOException + */ + public static KeyStore getKeyInfo(String pfxkeyfile,String keypwd,String type) throws Exception { + FileInputStream fis = null; + try { + + KeyStore ks = null; + ks = KeyStore.getInstance(type); + fis = new FileInputStream(pfxkeyfile); + char[] nPassword = null; + nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray(); + if (null != ks){ + ks.load(fis, nPassword); + } + return ks; + } catch (Exception e) { + throw e; + }finally{ + if(null!=fis){ + fis.close(); + } + } + } + + /** + * 获取签名证书私钥(单证书) + */ + public static PrivateKey getSignCertPrivateKey(String pfxPath,String pfxPwd)throws Exception { + if(keyStore == null){ + keyStore = initSignCert(pfxPath,pfxPwd); + } + Enumeration aliasenum = keyStore.aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, pfxPwd.toCharArray()); + return privateKey; + } + + /** + * 从指定目录书路径获取Certificate对象 + * @return + */ + public static Certificate initValidateCertFromDir(String crtPath) throws Exception { + CertificateFactory cf = null; + FileInputStream in = null; + try { + cf = CertificateFactory.getInstance(CERTFACTORY_TYPE); + in = new FileInputStream(crtPath); + validateCert = cf.generateCertificate(in); + } finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + throw e; + } + } + } + return validateCert; + } + + /** + * 根据证书路径获取Certificate对象 + */ + public static Certificate getValidateCert(String crtPath) throws Exception { + log.info("Cert starts loading...[certPath is:"+crtPath+"]"); + if(validateCert != null){ + log.info("cert is already exists,don't need to load it"); + return validateCert; + } + return initValidateCertFromDir(crtPath); + } + + /** + * 根据公钥字符串获取PublicKey对象 + * @return + */ + public static PublicKey getPubKeyObj(String pubKey)throws Exception { + java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(Base64Kit.decode(pubKey)); + // RSA对称加密算法 + KeyFactory keyFactory; + keyFactory = KeyFactory.getInstance("RSA"); + // 取公钥匙对象 + return keyFactory.generatePublic(bobPubKeySpec); + } + + /** + * 根据私钥字符串获取PrivateKey对象 + * @return + */ + public static PrivateKey getPriKeyObj(String priKeyStr) throws Exception { + PrivateKey privateKey; + PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Kit.decode(priKeyStr)); + KeyFactory keyf = KeyFactory.getInstance("RSA"); + privateKey = keyf.generatePrivate(priPKCS8); + return privateKey; + } + + /** + * 获取私钥字符串根据私钥证书和密码 + */ + public static String getPrivateKeyInfo(String privKeyFilePath,String privKeyPswd) throws Exception { + KeyStore keyStore = KeyStore.getInstance( KEYSTORE_TYPE); + FileInputStream fileInputStream = new FileInputStream(privKeyFilePath); + char[] nPassword; + if ((privKeyPswd == null) || privKeyPswd.trim().isEmpty()) { + nPassword = null; + } else { + nPassword = privKeyPswd.toCharArray(); + } + keyStore.load(fileInputStream, nPassword); + fileInputStream.close(); + Enumeration enumeration = keyStore.aliases(); + String keyAlias =""; + if (enumeration.hasMoreElements()) { + keyAlias = enumeration.nextElement(); + } + PrivateKey priKey = (PrivateKey) keyStore.getKey(keyAlias, nPassword); + return Base64Kit.toBase64String(priKey.getEncoded()); + } + + /** + * 获取公钥字符串 根据公钥证书 + */ + public static String getPublicKeyInfo(String publicKeyPath) throws Exception { + //获取X.509对象工厂 + CertificateFactory cf = CertificateFactory.getInstance(CERTFACTORY_TYPE); + //通过文件流读取证书文件 + X509Certificate cert = (X509Certificate)cf.generateCertificate(Files.newInputStream(Paths.get(publicKeyPath))); + //获取公钥对象 + PublicKey publicKey = cert.getPublicKey(); + return Base64Kit.toBase64String(publicKey.getEncoded()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/DesUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/DesUtil.java new file mode 100644 index 0000000..c9ed639 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/DesUtil.java @@ -0,0 +1,83 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + + +import hikefa.core.util.security.JDES; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author admin + */ +public class DesUtil { + private static Log log = LogFactory.getLog(DesUtil.class); + + /** + * 备注:DES加密key只能�?8�? + * 加密扩展数据 + * @param extraData + * @return + */ + public static String encryptExtraData(String key, String extraData) throws Exception { + String out = ""; + String charset = "UTF-8"; + log.info("加密(前)数据:" + extraData); + log.info("加密秘钥:" + key); + try { + if(StringUtils.isNotBlank(key)&&key.length()>8){ + key = key.substring(0,8); + } + JDES jd = new JDES(); + jd.SetKey(key.getBytes(charset)); + out = new String(Base64.encodeBase64(jd.doECBEncrypt( + extraData.getBytes(charset), + extraData.getBytes(charset).length))); + } catch (Exception e) { + log.error("进件参数加密异常", e); + } + log.info("加密(后)数据:" + out); + return out; + } + + /** + * + * @param key + * @param charset + * @param encryptExtraData + * @return + * @throws Exception + */ + public static String decryptExtraData(String key, String charset, String encryptExtraData) + throws Exception { + String out = ""; + log.info("解密(前)数据:" + encryptExtraData); + log.info("解密秘钥:" + key); + try { + if(StringUtils.isNotBlank(key)&&key.length()>8){ + key = key.substring(0,8); + } + JDES jd = new JDES(); + jd.SetKey(key.getBytes(charset)); + byte[] encryptByte = Base64.decodeBase64(encryptExtraData); + out = new String(jd.doECBDecrypt(encryptByte, + encryptByte.length), charset); + } catch (Exception e) { + log.error(e, e); + } + log.info("解密(后)数据:" + out); + return out; + } +// +// public static void main(String[] args)throws Exception { +// +// String key = "A81F41DE7406CC1566579A751D93CA7A"; +// String charset = "UTF-8";//UTF-8\GBK +// String str = "00#340103198907124036#银盛支付"; +// System.out.println("原�?�:"+str+" , 字符集:"+charset); +// String d = DesUtil.encryptExtraData(key,charset,str); +// System.out.println("加密�?"+d+" , 字符集:"+charset); +// String d1 = DesUtil.decryptExtraData(key,charset,d); +// System.out.println("解密�?"+d1+" , 字符集:"+charset); +// } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMCertInfo.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMCertInfo.java new file mode 100644 index 0000000..b3786b1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMCertInfo.java @@ -0,0 +1,111 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cfca.sadk.algorithm.sm2.SM2PublicKey; +import cfca.sadk.org.bouncycastle.jce.provider.BouncyCastleProvider; +import cfca.sadk.org.bouncycastle.util.encoders.Base64Kit; +import cfca.sadk.x509.certificate.X509Cert; +import lombok.Getter; +import lombok.Setter; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Serializable; +import java.security.PublicKey; +import java.security.Security; + +@Getter +@Setter +public class GMCertInfo implements Serializable +{ + private static final long serialVersionUID = 1L; + private SM2PublicKey pubKeySM2; + private PublicKey pubKey; + private byte[] priKey; + private X509Cert x509Cert; + + //读取原始公钥 + public static byte[] ReadPublicKeyFromRaw(String publickeyFile) throws Exception + { + FileInputStream br = null; + try { + br = new FileInputStream(publickeyFile); + byte[] b1 = new byte[2000]; + int k = br.read(b1); + byte[] b = new byte[k]; + System.arraycopy(b1, 0, b, 0, k); + return b; + } catch (IOException e) { + + throw e; + + } finally { + if(br != null){ + br.close(); + } + } + } + + // 从X509证书文件读取公钥,Certificate只含有公钥 + // .crt .cer文件都可以读取 .cer是IE导出的公钥证书(der格式) + // -----BEGIN CERTIFICATE-----开始 文件头不许有其它内容 + // -----END CERTIFICATE----- + // cer公钥证书 二进制 + public void ReadPublicKeyFromX509CertificateSM2(String cerFilePath) throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + byte[] cer = ReadPublicKeyFromRaw(cerFilePath); + ReadPublicKeyFromX509CertificateSM2(cer); + } + + public void ReadPublicKeyFromX509CertificateSM2Str(String pubKey) throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + ReadPublicKeyFromX509CertificateSM2(Base64Kit.decode(pubKey)); + } + + + public void ReadPublicKeyFromX509CertificateSM2(byte[] cer) throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + x509Cert = new X509Cert(cer); + //获取公钥对象 + pubKeySM2 = (SM2PublicKey) x509Cert.getPublicKey(); + pubKey = x509Cert.getPublicKey(); + } + + public SM2PublicKey getPubKeySM2() { + return pubKeySM2; + } + + public void setPubKeySM2(SM2PublicKey pubKeySM2) { + this.pubKeySM2 = pubKeySM2; + } + + public PublicKey getPubKey() { + return pubKey; + } + + public void setPubKey(PublicKey pubKey) { + this.pubKey = pubKey; + } + + public byte[] getPriKey() { + return priKey; + } + + public void setPriKey(byte[] priKey) { + this.priKey = priKey; + } + + public X509Cert getX509Cert() { + return x509Cert; + } + + public void setX509Cert(X509Cert x509Cert) { + this.x509Cert = x509Cert; + } + + + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMSignUtils.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMSignUtils.java new file mode 100644 index 0000000..a79071d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/GMSignUtils.java @@ -0,0 +1,268 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cfca.sadk.algorithm.common.Mechanism; +import cfca.sadk.algorithm.common.MechanismKit; +import cfca.sadk.algorithm.sm2.SM2PublicKey; +import cfca.sadk.lib.crypto.JCrypto; +import cfca.sadk.lib.crypto.Session; +import cfca.sadk.org.bouncycastle.util.encoders.Base64Kit; +import cfca.sadk.util.EnvelopeUtil; +import cfca.sadk.util.KeyUtil; +import cfca.sadk.util.Signature; +import cfca.sadk.x509.certificate.X509Cert; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.security.PrivateKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +/** + * @类名称:GMSignUtil + * @类描述:国密算法SM2签名工具类 + * @作者:zhanggy + * @日期:2021年8月11日 + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GMSignUtils { + + /** + * 国密算法数据加密(SM2公钥加密:长度通常限定为136字节内) + * @param src + * @param data + * @throws Exception + */ + public static String encryptData(String src, String data) throws Exception { + String encryptMsg = null; + GMCertInfo certInfo = getVerifyCertInfo(src); + try { + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + final Session session = JCrypto.getInstance().openSession(deviceName); + // 一个或者多个加密证书 + X509Cert[] recvcerts = new X509Cert[] { certInfo.getX509Cert() }; + byte[] base64Bytes = EnvelopeUtil.envelopeMessage(data.getBytes("UTF-8"), Mechanism.SM4_ECB, recvcerts, session); + encryptMsg = new String(base64Bytes); + } catch (Exception e) { + throw new Exception("数据SM2加密失败"); + } + return encryptMsg; + } + + /** + * 国密算法数据加密(SM2公钥加密:长度通常限定为136字节内) + * @param data + * @throws Exception + */ + public static String encryptDataStr(String crtStr,String data) throws Exception { + String encryptMsg = null; + GMCertInfo certInfo = getVerifyCertInfoStr(crtStr); + try { + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + final Session session = JCrypto.getInstance().openSession(deviceName); + // 一个或者多个加密证书 + X509Cert[] recvcerts = new X509Cert[] { certInfo.getX509Cert() }; + byte[] base64Bytes = EnvelopeUtil.envelopeMessage(data.getBytes("UTF-8"), Mechanism.SM4_ECB, recvcerts, session); + encryptMsg = new String(base64Bytes); + } catch (Exception e) { + throw new Exception("数据SM2加密失败"); + } + return encryptMsg; + } + + /** + * 获取支付平台公钥证书 + * @param src + * @return + * @throws Exception + */ + public static GMCertInfo getVerifyCertInfo(String src) throws Exception { + GMCertInfo certInfo = new GMCertInfo(); + try{ + certInfo.ReadPublicKeyFromX509CertificateSM2(src); + } catch (Exception e) { + throw new Exception("银盛平台公钥证书加载失败"); + } + + return certInfo; + } + + /** + * 获取支付平台公钥证书 + * @param pubKey + * @return + * @throws Exception + */ + public static GMCertInfo getVerifyCertInfoStr(String pubKey) throws Exception { + GMCertInfo certInfo = new GMCertInfo(); + try{ + certInfo.ReadPublicKeyFromX509CertificateSM2Str(pubKey); + } catch (Exception e) { + throw new Exception("银盛平台公钥证书加载失败"); + } + + return certInfo; + } + + /** + * 加载公钥证书 + * @return + * + */ + public synchronized static GMCertInfo initValidateCert(byte[] bs,String certId) { + GMCertInfo certInfo = new GMCertInfo(); + try { + certInfo.ReadPublicKeyFromX509CertificateSM2(bs); + return certInfo; + } catch (Exception e) { + log.info("银盛平台公钥证书加载失败", e); + } + return certInfo; + } + + /** + * 国密算法验证签名(报文) + * @param certInfo + * @param bcheck + * @param xmlMsg + * @throws Exception + */ + public static boolean verifyMsgSignSM2(GMCertInfo certInfo, byte[] bcheck, byte[] xmlMsg){ + boolean bFlag; + try{ + SM2PublicKey pubKey = certInfo.getPubKeySM2(); + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + Session session = JCrypto.getInstance().openSession(deviceName); + final Signature util = new Signature(); + final String signAlg = MechanismKit.SM3_SM2;//SM3WithSM2 + // 校验,必须指定签名算法 + bFlag = util.p1VerifyMessage(signAlg,xmlMsg,bcheck,pubKey,session); + } catch (Exception e) { + bFlag = false; + log.info("国密验签失败", e); + } + return bFlag; + } + + /** + * 获取商户私钥证书 + * @param src + * @return + * @throws Exception + */ + public synchronized static GMCertInfo getSignCertInfo(String src) throws Exception { + //商户私钥证书 + String certfile = src; + log.info("证书路经---"+certfile); + GMCertInfo certInfo = new GMCertInfo(); + try { + byte[] priKeySm2 = YspayKit.readFile(certfile); + certInfo.setPriKey(priKeySm2); + } catch (Exception e) { + throw new Exception("商户签名证书加载失败"); + } + + return certInfo; + } + + /** + * 获取商户私钥证书 + * @param priKeyStr + * @return + * @throws Exception + */ + public synchronized static GMCertInfo getSignCertInfoStr(String priKeyStr) throws Exception { + //商户私钥证书 + GMCertInfo certInfo = new GMCertInfo(); + try { + byte[] priKeySm2 = Base64Kit.decode(priKeyStr); + certInfo.setPriKey(priKeySm2); + } catch (Exception e) { + throw new Exception("商户签名证书加载失败"); + } + + return certInfo; + } + + /** + * 国密算法签名(报文) + * @param sm2FilePath + * @param msg + * @return 返回 256长度base64编码 + * @throws Exception + */ + public synchronized static String signMsgSM2(String sm2FilePath,String passWord, String msg) throws Exception { + GMCertInfo certInfo = getSignCertInfo(sm2FilePath); + // 返回的是256位 + byte[] signed; + try { + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + Session session = JCrypto.getInstance().openSession(deviceName); + PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(certInfo.getPriKey(),passWord); +// PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(certInfo.getPriKey(),"ys123456"); + byte[] sourceData = msg.getBytes(); + Signature util = new Signature(); + String signAlg = Mechanism.SM3_SM2;//SM3WithSM2 + // 签名,必须指定签名算法,返回BASE64签名结果 + signed = util.p1SignMessage(signAlg, sourceData, priKey, session); + } catch (Exception e) { + throw new Exception("报文SM2签名失败"); + } + String checkValue = new String(signed); + return String.format("%-256s", checkValue); + } + + /** + * 国密算法签名(报文) + * @param msg + * @return 返回 256长度base64编码 + * @throws Exception + */ + public synchronized static String signMsgSM2Str(String priKeyStr,String passWord, String msg) throws Exception { + GMCertInfo certInfo = getSignCertInfoStr(priKeyStr); + // 返回的是256位 + byte[] signed; + try { + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + Session session = JCrypto.getInstance().openSession(deviceName); + PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(certInfo.getPriKey(),passWord); +// PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(certInfo.getPriKey(),"ys123456"); + byte[] sourceData = msg.getBytes(); + Signature util = new Signature(); + String signAlg = Mechanism.SM3_SM2;//SM3WithSM2 + // 签名,必须指定签名算法,返回BASE64签名结果 + signed = util.p1SignMessage(signAlg, sourceData, priKey, session); + } catch (Exception e) { + throw new Exception("报文SM2签名失败"); + } + String checkValue = new String(signed); + return String.format("%-256s", checkValue); + } + + public static String getSignDataStr1(Map map) { + List keys = new ArrayList<>(map.keySet()); + Collections.sort(keys); + StringBuilder sb = new StringBuilder(); + for(String key : keys){ + if("sign".equals(key)) { + continue; + } + sb.append(key).append("="); + sb.append(map.get(key)); + sb.append("&"); + } + if(sb.length() > 0) { + sb.setLength(sb.length() - 1); + } + return sb.toString(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/HttpRequestUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/HttpRequestUtil.java new file mode 100644 index 0000000..acd5a1c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/HttpRequestUtil.java @@ -0,0 +1,98 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.nio.charset.Charset; +import java.util.Map; + +public class HttpRequestUtil { + + /** + * 图片上传接口,未校验文件名称,商户进件需要用到 + * @param url + * @param paramMap + * @param file + * @return + * @throws Exception + */ + public static String sendPostFile(String url, Map paramMap, File file) throws Exception { + HttpPost httpPost = new HttpPost(url); + //如果返回403 增加一下代码模拟浏览器 + //httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0");; + + CloseableHttpClient client = HttpClientBuilder.create().build(); + + MultipartEntityBuilder entity = MultipartEntityBuilder.create() + .setContentType(ContentType.MULTIPART_FORM_DATA) + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .addBinaryBody("file", new FileInputStream(file), ContentType.DEFAULT_BINARY, file.getName()) //uploadFile对应服务端类的同名属性 + .setCharset(Charset.forName("utf-8")); + + for (String key : paramMap.keySet()) { + String value = paramMap.get(key); + entity.addTextBody(key, value); + } + + httpPost.setEntity(entity.build()); + HttpResponse httpResponse = client.execute(httpPost); + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + System.out.println(httpResponse.getStatusLine().getStatusCode()); + } + + HttpEntity resEntity = httpResponse.getEntity(); + return null == resEntity ? "" : EntityUtils.toString(resEntity, "utf-8"); + } + + /** + * 文件上传 校验了文件名称,支付宝实名认证文件上传用到 + * @param url + * @param paramMap + * @param file + * @param fileName + * @return + * @throws Exception + */ + public static String sendPostFileAndName(String url, Map paramMap, File file,String fileName) throws Exception { + if(StringUtils.isEmpty(fileName)){ + throw new Exception("文件名称不能为空"); + } + HttpPost httpPost = new HttpPost(url); + //如果返回403 增加一下代码模拟浏览器 + //httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0");; + + CloseableHttpClient client = HttpClientBuilder.create().build(); + + MultipartEntityBuilder entity = MultipartEntityBuilder.create() + .setContentType(ContentType.MULTIPART_FORM_DATA) + .setMode(HttpMultipartMode.BROWSER_COMPATIBLE) + .addBinaryBody("file", new FileInputStream(file), ContentType.DEFAULT_BINARY, fileName) //uploadFile对应服务端类的同名属性 + .setCharset(Charset.forName("utf-8")); + + for (String key : paramMap.keySet()) { + String value = paramMap.get(key); + entity.addTextBody(key, value); + } + + httpPost.setEntity(entity.build()); + HttpResponse httpResponse = client.execute(httpPost); + if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + System.out.println(httpResponse.getStatusLine().getStatusCode()); + } + + HttpEntity resEntity = httpResponse.getEntity(); + return null == resEntity ? "" : EntityUtils.toString(resEntity, "utf-8"); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/RSA256Util.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/RSA256Util.java new file mode 100644 index 0000000..a61cbe6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/RSA256Util.java @@ -0,0 +1,118 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cfca.sadk.org.bouncycastle.util.encoders.Base64Kit; +import cn.hutool.core.io.FileUtil; +import cn.hutool.crypto.SecureUtil; + +import javax.crypto.Cipher; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; + + +public class RSA256Util { + + private static final String ALGORITHM = "SHA256withRSA"; + + private static final String ALGORITHM_PKCS1PADDING = "RSA/ECB/PKCS1Padding"; + + private static final String CHARSET = "utf-8"; + + /** + * 签名算法 + * @param data 待签名的数据 + * @return + */ + public static String sign(String data,String pfxPath,String pfxPwd) throws Exception { + KeyStore pkcs12 = SecureUtil.readKeyStore("PKCS12", FileUtil.getInputStream(pfxPath), pfxPwd.toCharArray()); + PrivateKey privateKey = SecureUtil.generatePrivateKey(pkcs12, pkcs12.aliases().nextElement(), pfxPwd.toCharArray()); + return Base64Kit.toBase64String(RSA256Util.signBySoft(privateKey, data.getBytes(CHARSET))); + } + + /** + * 签名算法 + * @param data 待签名的数据 + * @return + */ + public static String signCrtStr(String data,String pfxStr,String pfxPwd) throws Exception { + PrivateKey privateKey = CertUtil.getPriKeyObj(pfxStr); + return Base64Kit.toBase64String(RSA256Util.signBySoft(privateKey, data.getBytes(CHARSET))); + } + + /** + * @param privateKey 私钥 + * @param data 待签名的数据 + * @return + * @throws Exception + */ + public static byte[] signBySoft(PrivateKey privateKey, byte[] data) throws Exception { + Signature st = Signature.getInstance(ALGORITHM); + st.initSign(privateKey); + st.update(data); + byte[] result = st.sign(); + return result; + } + + /** + * 根据公钥证书路径去验证签名 + */ + public static boolean validateSign(String crtPath,byte[] signData, byte[] srcData) throws Exception { + return RSA256Util.validateSignBySoft(CertUtil.getValidateCert(crtPath).getPublicKey(), signData, srcData); + } + + /** + * @Author 胡兴铭 + * @Description 通过公钥字符串进行验签 + * @Date 13:50 2021/10/20 + * @Param + * @return + */ + public static boolean validateSignCrtStr(String crtStr,byte[] signData, byte[] srcData) throws Exception { + return RSA256Util.validateSignBySoft(CertUtil.getPubKeyObj(crtStr), signData, srcData); + } + /** + * 软验证签名 + * + * @param publicKey + * 公钥 + * @param signData + * 签名数据 + * @param srcData + * 摘要 + * 签名方法. + * @return + * @throws Exception + */ + public static boolean validateSignBySoft(PublicKey publicKey,byte[] signData, byte[] srcData) throws Exception { + Signature st = Signature.getInstance(ALGORITHM); + st.initVerify(publicKey); + st.update(srcData); + return st.verify(signData); + } + + /** + * @Param + * @return + */ + public static byte[] encrypt(String crtPath,byte[] content) throws Exception{ + Cipher cipher=Cipher.getInstance(ALGORITHM_PKCS1PADDING); + cipher.init(Cipher.ENCRYPT_MODE, CertUtil.getValidateCert(crtPath).getPublicKey()); + return cipher.doFinal(content); + } + + + /** + * @Author 胡兴铭 + * @Description 根据公钥字符串加密 + * @Date 11:41 2021/10/20 + * @Param + * @return + */ + public static byte[] encryptCrtStr(String crtStr,byte[] content) throws Exception{ + Cipher cipher=Cipher.getInstance(ALGORITHM_PKCS1PADDING); + cipher.init(Cipher.ENCRYPT_MODE, CertUtil.getPubKeyObj(crtStr)); + return cipher.doFinal(content); + } +} + diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignRsaUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignRsaUtil.java new file mode 100644 index 0000000..e035ecb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignRsaUtil.java @@ -0,0 +1,115 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.codec.binary.Base64; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Enumeration; +import java.util.Map; + + +@Slf4j +public class SignRsaUtil { + + + //使用RSA的加密算法对以上字符串进行签名并进行Base64编码 + public static String rsaSign(PrivateKey privateKey, String content, String charset) throws Exception { + Signature signet = Signature.getInstance("SHA1WithRSA"); + signet.initSign(privateKey); + signet.update(content.getBytes(charset)); + byte[] signed = signet.sign(); + return new String(Base64.encodeBase64(signed), charset); + } + + /** 获取证书私钥 **/ + public static PrivateKey getSignCertPrivateKey(String pfxkeyfile, String keypwd) { + FileInputStream fis = null; + try { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + fis = new FileInputStream(pfxkeyfile); + char[] nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray(); + if (null != keyStore) { + keyStore.load(fis, nPassword); + } + Enumeration aliasenum = keyStore.aliases(); + String keyAlias = null; + if (aliasenum.hasMoreElements()) { + keyAlias = aliasenum.nextElement(); + } + PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keypwd.toCharArray()); + return privateKey; + } catch (Exception e) { + log.error("获取证书私钥失败!", e); + return null; + }finally { + if(null!=fis) { + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 异步通知参数验签 + */ + public static boolean asynVerifyYsRsa(FileInputStream fileInputStream, Map reqMap) throws Exception { + boolean flag = false; + //请用银盛的公钥证书 + PublicKey ysPayPublicKey = getPublicKeyFromCert(fileInputStream); + + String sign = reqMap.get("sign").trim(); + reqMap.remove("sign"); + System.out.println("签名原文:"+reqMap); + String content = YspayKit.getSignContent(reqMap); + System.out.println("验签数据"+content+","+sign); + Signature signetcheck = Signature.getInstance("SHA1WithRSA"); + signetcheck.initVerify(ysPayPublicKey); + signetcheck.update(content.getBytes(StandardCharsets.UTF_8)); + if (signetcheck.verify(Base64.decodeBase64(sign.getBytes(StandardCharsets.UTF_8)))) { + flag = true; + } + + return flag; + } + + /** + * 读取公钥,x509格式 + * + * @param ins + * @return + * @throws Exception + * @see + */ + public static PublicKey getPublicKeyFromCert(InputStream ins) throws Exception { + PublicKey pubKey = null; + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate cac = cf.generateCertificate(ins); + pubKey = cac.getPublicKey(); + } catch (Exception e) { + if (ins != null){ + ins.close(); + } + throw e; + } finally { + if (ins != null) { + ins.close(); + } + } + + return pubKey; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignSmUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignSmUtil.java new file mode 100644 index 0000000..7aba6f6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignSmUtil.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cfca.sadk.algorithm.common.Mechanism; +import cfca.sadk.lib.crypto.JCrypto; +import cfca.sadk.lib.crypto.Session; +import cfca.sadk.util.KeyUtil; +import cfca.sadk.util.Signature; +import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.codec.binary.Base64; + +import java.security.PrivateKey; +import java.util.Map; + + +@Slf4j +public class SignSmUtil { + + + /** + * 国密算法签名(报文) + * @param sm2FilePath + * @param msg + * @return 返回 256长度base64编码 + * @throws Exception + */ + public synchronized static String signMsgSM2(String sm2FilePath, String passWord, String msg) throws Exception { + // 返回的是256位 + byte[] signed; + try { + final String deviceName = JCrypto.JSOFT_LIB; + JCrypto.getInstance().initialize(deviceName, null); + Session session = JCrypto.getInstance().openSession(deviceName); + PrivateKey priKey = KeyUtil.getPrivateKeyFromSM2(YspayKit.readFile(sm2FilePath), passWord); + byte[] sourceData = msg.getBytes(); + Signature util = new Signature(); + String signAlg = Mechanism.SM3_SM2;//SM3WithSM2 + // 签名,必须指定签名算法,返回BASE64签名结果 + signed = util.p1SignMessage(signAlg, sourceData, priKey, session); + } catch (Exception e) { + log.error("", e); + throw new Exception("报文SM2签名失败"); + } + String checkValue = new String(signed); + return String.format("%-256s", checkValue); + } + + + + /** + * 异步通知参数验签 + */ + public static boolean asynVerifyYsSm(String sm2FilePath, Map reqMap) throws Exception { + //请用银盛的公钥证书 + //公钥地址 + //获取银盛公钥 + GMCertInfo verifyCertInfo = GMSignUtils.getVerifyCertInfo(sm2FilePath); + //验签 + String sign = reqMap.get("sign").trim(); + reqMap.remove("sign"); + System.out.println("签名原文:"+reqMap); + String content = YspayKit.getSignContent(reqMap); + System.out.println("验签数据"+content+","+sign); + byte[] srcData = content.getBytes("UTF-8"); + boolean validateSignResult = GMSignUtils.verifyMsgSignSM2(verifyCertInfo, Base64.decodeBase64(sign.getBytes("UTF-8")), srcData); + + return validateSignResult; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignUtil.java new file mode 100644 index 0000000..8685d2f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/SignUtil.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + + +import java.security.PublicKey; +import java.security.Signature; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class SignUtil { + + private static final String ALGORITHM = "SHA256withRSA"; + + /** + * @Author 胡兴铭 + * @Description 验签 + * @Date 10:38 2020/3/12 + * @Param + * @return + */ + public static boolean signVerify(Map map, String signData,PublicKey publicKey)throws Exception { + byte[] srcData = getSignDataStr(map).getBytes("utf-8"); + return validateSignBySoft(publicKey, org.apache.commons.codec.binary.Base64.decodeBase64(signData), srcData); + } + + public static boolean validateSignBySoft(PublicKey publicKey,byte[] signData, byte[] srcData) throws Exception { + Signature st = Signature.getInstance(ALGORITHM); + st.initVerify(publicKey); + st.update(srcData); + return st.verify(signData); + } + + public static String getSignDataStr(Map map) { + List keys = new ArrayList(map.keySet()); + Collections.sort(keys); + StringBuilder sb = new StringBuilder(); + for(String key : keys){ + if("sign".equals(key)) { + continue; + } + sb.append(key).append("="); + sb.append(map.get(key)); + sb.append("&"); + } + if(sb.length() > 0) { + sb.setLength(sb.length() - 1); + } + return sb.toString(); + } + + public static String getSignDataStr1(Map map) { + List keys = new ArrayList(map.keySet()); + Collections.sort(keys); + StringBuilder sb = new StringBuilder(); + for(String key : keys){ + if("sign".equals(key)) { + continue; + } + if("$jacocoData".equals(key)) { + continue; + } + sb.append(key).append("="); + sb.append(map.get(key)); + sb.append("&"); + } + if(sb.length() > 0) { + sb.setLength(sb.length() - 1); + } + return sb.toString(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/YspayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/YspayKit.java new file mode 100644 index 0000000..4f21a75 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/yspay/utils/YspayKit.java @@ -0,0 +1,887 @@ +package com.jeequan.jeepay.thirdparty.channel.yspay.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.*; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.utils.Base64; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.yspay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.util.*; + + +@Slf4j +public class YspayKit { + private static final String ALLCHAR = "0123456789ABCDEF"; + + private static final String BASEURL = "https://qrcode.ysepay.com/gateway.do"; + + // public static final String APPLYMENT_URL = "https://ouser.ysepay.com:6443"; + // public static final String APPLYMENT_URL = "https://appdev.ysepay.com"; + public static final String APPLYMENT_URL = "https://ysgate.ysepay.com"; + /** + * 分账请求地址 + **/ + public static final String DIVISION_URL = "https://commonapi.ysepay.com/gateway.do"; + /** + * 分账退款接口 + **/ + public static final String DIVISION_REFUND_URL = "https://openapi.ysepay.com/gateway.do"; + + public static final String RES_CODE = "10000"; // 响应状态 + public static final String APPLY_CODE = "00000"; // 进件网关响应码,00000表示请求成功 + public static final String APPLY_SUB_CODE = "0000"; // 进件业务响应码,0000表示成功 + + public static final String TRADE_SUCCESS = "TRADE_SUCCESS"; // 交易成功 + public static final String TRADE_PROCESS = "TRADE_PROCESS"; // 交易处理中 + public static final String WAIT_BUYER_PAY = "WAIT_BUYER_PAY"; // 交易中 + public static final String TRADE_FAILED = "TRADE_FAILED"; // 交易失败 + public static final String TRADE_ALL_REFUND = "TRADE_ALL_REFUND"; // 全部退款成功 + public static final String TRADE_PART_REFUND = "TRADE_PART_REFUND"; // 部分退款成功 + + public static final String POS_CODE_S = "S"; // 成功 + public static final String POS_CODE_F = "F"; // 失败 + public static final String POS_CODE_T = "T"; // 发送超时 + + private static final String REQ_TYPE_PAYMENT = "pay"; // 支付类型签名-支付 + private static final String REQ_TYPE_APPLYMENT = "apply"; // 支付类型签名-进件 + + public static String payRequest(String reqUrl, String method, MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String notifyUrl, String ifCode) { + + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode); + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + // 接口名称 + reqParams.put("method", method); + // 版本号 + reqParams.put("version", "3.0"); + // 回调地址 + if (StringUtils.isNotEmpty(notifyUrl)) { + reqParams.put("notify_url", notifyUrl); + } + // 签名方式 + reqParams.put("sign_type", isvParams.getSignType()); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求的时间 + reqParams.put("timestamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 通道服务商号 + reqParams.put("partner_id", isvParams.getPartnerId()); + // 请求参数 + reqParams.put("biz_content", bizContent.toJSONString()); + + // 支付下单类型 + reqParams.put("reqType", REQ_TYPE_PAYMENT); + // 生成签名 + String sign = getSign(isvParams, reqParams); + reqParams.put("sign", sign); + // 发起请求 + log.info("【银盛支付】发起请求:{}", reqParams); + String response = HttpUtil.post(reqUrl, reqParams); + log.info("【银盛支付】响应结果:{}", response); + return response; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static String payRequest(String method, MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String notifyUrl, String ifCode) { + try { + return payRequest(BASEURL, method, mchAppConfigContext, bizContent, notifyUrl, ifCode); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static String divisionRequest(String reqUrl, String method, String isvNo, JSONObject bizContent, String notifyUrl, String ifCode) { + + // 配置参数 + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(isvNo, ifCode); + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + // 接口名称 + reqParams.put("method", method); + // 通道服务商号 + reqParams.put("partner_id", isvParams.getPartnerId()); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求的时间 + reqParams.put("timestamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 签名方式 + reqParams.put("sign_type", isvParams.getSignType()); + // 版本号 + reqParams.put("version", "3.0"); + // 回调地址 + if (StringUtils.isNotEmpty(notifyUrl)) { + reqParams.put("notify_url", notifyUrl); + } + // 请求参数 + reqParams.put("biz_content", bizContent.toJSONString()); + // 签名类型 + reqParams.put("reqType", REQ_TYPE_PAYMENT); + + // 生成签名 + String sign = getSign(isvParams, reqParams); + reqParams.put("sign", sign); + // 发起请求 + log.info("【银盛分账】发起请求:{}", reqParams); + String response = HttpUtil.post(reqUrl, reqParams); + log.info("【银盛分账】响应结果:{}", response); + return response; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static String wxQueryRequest(String reqUrl, String notifyUrl, String method, YspayIsvParams isvParams, JSONObject bizContent) { + + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + // 接口名称 + reqParams.put("method", method); + // 版本号 + reqParams.put("version", "3.0"); + // 签名方式 + reqParams.put("sign_type", isvParams.getSignType()); + // 回调地址 + if (StringUtils.isNotEmpty(notifyUrl)) { + reqParams.put("notify_url", notifyUrl); + } + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求的时间 + reqParams.put("timestamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 通道服务商号 + reqParams.put("partner_id", isvParams.getPartnerId()); + // 请求参数 + reqParams.put("biz_content", bizContent.toJSONString()); + // 生成签名 + String sign = getSign(isvParams, reqParams).trim(); + + if ("ysepay.merchant.scan.report".equals(method) && "SM".equals(isvParams.getSignType())) { + sign = Base64.encodeBase64String(sign.getBytes(StandardCharsets.UTF_8)); + } + + reqParams.put("sign", sign); + // 发起请求 + log.info("【银盛支付】请求地址:{}, 发起请求:{}", reqUrl, reqParams); + String response = HttpUtil.post(reqUrl, reqParams); + log.info("【银盛支付】请求地址:{}, 响应结果:{}", reqUrl, response); + return response; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static void setPayParams(MchAppConfigContext mchAppConfigContext, JSONObject bizContent, String payType, String ifCode) { + bizContent.put("seller_id", mchAppConfigContext.getMchApplyment().getChannelMchNo()); + // 商户名 +// bizContent.put("seller_name", mchParams.getMercCnm()); + // 业务代码 00510030 正扫微信、二维码、银联行业码、反扫(T1/D1) + // 正扫微信、二维码、银联行业码(D0):00510032 + // 反扫(D0):00510080 + if(CS.SETTLEMENT_TYPE.D0.equals(mchAppConfigContext.getMchApplyment().getSettlementType())){ + if ("1".equals(payType)) { + // 主扫 D0 + bizContent.put("business_code", "00510032"); + } else { + // 反扫 D0 + bizContent.put("business_code", "00510080"); + } + }else{ + bizContent.put("business_code", "00510030"); + } + } + + /** + * 生成签名 + * + * @param isvParams + * @param reqParams + * @return + */ + public static String getSign(YspayIsvParams isvParams, JSONObject reqParams) { + try { + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String certFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPrivateKeyFile()); + + String reqType = reqParams.getString("reqType"); + reqParams.remove("reqType"); + Map paramsMap = reqParams.toJavaObject(Map.class); + String signContent = getSignContent(paramsMap); + log.info("【银盛支付】待签名内容:{}, 证书地址:{}", signContent, certFilePath); + String sign = null; + if ("RSA".equals(isvParams.getSignType())) { + if (StringUtils.isNotEmpty(reqType) && REQ_TYPE_PAYMENT.equals(reqType)) { + PrivateKey privateKey = SignRsaUtil.getSignCertPrivateKey(certFilePath, isvParams.getPrivateKeyPassword()); + sign = SignRsaUtil.rsaSign(privateKey, signContent, "utf-8"); + } else { + sign = RSA256Util.sign(signContent, certFilePath, isvParams.getPrivateKeyPassword()); + } + } else if ("SM".equals(isvParams.getSignType())) { + sign = SignSmUtil.signMsgSM2(certFilePath, isvParams.getPrivateKeyPassword(), signContent); + } else { + log.error("未识别的签名类型"); + } + log.info("【银盛支付】签名结果:{}", sign); + return sign; + } catch (Exception e) { + e.printStackTrace(); + throw new BizException("【银盛支付】签名异常:" + e.getMessage()); + } + } + + /** + * 遍历以及根据重新排序 + * + * @param sortedParams + * @return + */ + public static String getSignContent(Map sortedParams) { + StringBuffer content = new StringBuffer(); + List keys = new ArrayList(sortedParams.keySet()); + Collections.sort(keys); + int index = 0; + for (int i = 0; i < keys.size(); i++) { + String key = keys.get(i); + String value = sortedParams.get(key); + if (!StringUtils.isAnyEmpty(key, value)) { + content.append((index == 0 ? "" : "&") + key + "=" + value); + index++; + } + } + return content.toString(); + } + + + /** + * 读文件 + * + * @param file 文件路径 + * @return 文件内容 + * @throws IOException + */ + public static final byte[] readFile(String file) throws IOException { + int offset = 0; + FileInputStream in = null; + try { + in = new FileInputStream(file); + byte[] out = new byte[in.available()]; + + if (out.length < offset + in.available()) { + throw new IOException("Illegal Argument: filepath"); + } + + byte[] buffer = new byte[1024]; + int numRead; + while ((numRead = in.read(buffer, 0, buffer.length)) >= 0) { + System.arraycopy(buffer, 0, out, offset, numRead); + offset += numRead; + } + return out; + } catch (Exception e) { + + throw e; + + } finally { + if (in != null) { + in.close(); + } + } + } + + +//--------------------------------------------------------------------------------------------------------------------------- + + /** + * 发起进件请求 + * + * @param reqUrl + * @param method + * @param isvParams + * @param bizContent + * @return + */ + public static String applymentRequest(String reqUrl, String method, YspayIsvParams isvParams, JSONObject bizContent) { + return applymentRequest(reqUrl, method, isvParams, bizContent, null); + } + + /** + * 发起进件请求 + * + * @param reqUrl + * @param method + * @param isvParams + * @param bizContent + * @param imgFileByteArray 要上传的文件 + * @return + */ + public static String applymentRequest(String reqUrl, String method, YspayIsvParams isvParams, JSONObject bizContent, byte[] imgFileByteArray) { + + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + // 接口名称 + reqParams.put("method", method); + // 请求的时间 + reqParams.put("timeStamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求流水号 + reqParams.put("reqId", DateKit.currentTimeMillis() + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN)); + // 通道服务商号 + reqParams.put("certId", isvParams.getPartnerId()); + // 版本号 + reqParams.put("version", "1.0"); + + /** 2、生成对业务参数加密的密钥*/ + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 16; i++) { + sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); + } + String key = ByteUtil.toHexString(sb.toString()); + + /** 3、使用银盛公钥对密钥key进行加密,得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/ + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String publicKeyFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + String check = null; + + BufferedInputStream inputStream = FileUtil.getInputStream(publicKeyFilePath); + byte[] publicKeyEncoded = SecureUtil.readX509Certificate(inputStream).getPublicKey().getEncoded(); + SM2 sm2 = null; + RSA rsa = null; + if ("SM".equals(isvParams.getSignType())) { + sm2 = SmUtil.sm2(null, publicKeyEncoded); + check = sm2.encryptBase64(publicKeyFilePath, KeyType.PublicKey); + } else if ("RSA".equals(isvParams.getSignType())) { + rsa = SecureUtil.rsa(null, publicKeyEncoded); + check = rsa.encryptBase64(ByteUtil.hexStringToBytes(key), KeyType.PublicKey); + } + + //加密后的密钥 + reqParams.put("check", check); + + /** 4、封装业务参数 */ + + /** 5、使用生成的密钥key对业务参数进行加密,并将加密后的业务参数放入请求参数bizContent中*/ + byte[] bte = AESUtil.encrypt(JSON.toJSONBytes(bizContent, SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key)); + reqParams.put("bizContent", org.apache.tomcat.util.codec.binary.Base64.encodeBase64String(bte)); + + + /** 6、将请求参数进行sort排序,生成拼接的字符床,并使用接入方私钥对请求参数进行加签,并将加签的值存入请求参数sign中*/ + String sign = getSign(isvParams, reqParams); + reqParams.put("sign", sign); + + /** 7、发送http请求获取返回结果 */ + log.info("【银盛进件】请求地址:{},发起请求:{},加密前bizContent:{}", APPLYMENT_URL + reqUrl, reqParams, bizContent); + String result; + if (imgFileByteArray == null) { + result = HttpRequest.post(APPLYMENT_URL + reqUrl) + .header("Content-type", "application/json") + .timeout(20000) + .charset("UTF-8") + .body(reqParams.toJSONString()) + .execute() + .body(); + } else { + result = HttpUtil.createPost(APPLYMENT_URL + reqUrl) + .form("file", imgFileByteArray, "1.png") + .form(JSON.toJavaObject(reqParams, Map.class)) + .execute().body(); + } + + + byte[] res = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(result); + Map resMap = (Map) JSONObject.parse(new String(res, StandardCharsets.UTF_8)); + log.info("【银盛接口】响应结果:{}", JSON.toJSONString(resMap)); + + /** 8、对结果进行解密,并使用银盛公钥验签*/ + if (StringUtils.isNotBlank(resMap.get("sign"))) { + if ("SM".equals(isvParams.getSignType())) { + byte[] srcData = GMSignUtils.getSignDataStr1(resMap).getBytes("UTF-8"); + boolean validateSignResult1 = sm2.verify(srcData, Base64.decodeBase64(resMap.get("sign").getBytes(StandardCharsets.UTF_8))); + if (!validateSignResult1) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } else if ("RSA".equals(isvParams.getSignType())) { + byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes(StandardCharsets.UTF_8); + Sign sign2 = cn.hutool.crypto.SignUtil.sign(SignAlgorithm.SHA256withRSA, null, publicKeyEncoded); + boolean validateSignResult1 = sign2.verify(srcData, Base64.decodeBase64(resMap.get("sign").getBytes(StandardCharsets.UTF_8))); + if (!validateSignResult1) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } + } else { + throw new BizException("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}" + resMap.get("msg")); + } + + /** 9、针对自己的业务,根据返回的结果的code 和 subCode 做接入方的业务处理*/ + if (!APPLY_CODE.equals(resMap.get("code"))) { + throw new BizException(StringUtils.isBlank(resMap.get("msg")) ? "请求响应失败" : resMap.get("msg")); + } + if (!APPLY_SUB_CODE.equals(resMap.get("subCode"))) { + if ("B510091".equals(resMap.get("subCode"))) { + throw new BizException(ApiCodeEnum.YS_ARTIFICIAL_AUDIT_CODE); + } + + throw new BizException(StringUtils.isBlank(resMap.get("subMsg")) ? "业务响应失败" : resMap.get("subMsg")); + } + + /** 10、使用上面生成的加密密钥key,解密返回的业务参数*/ + if (StringUtils.isNotBlank(resMap.get("businessData"))) { + byte[] data_ = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(resMap.get("businessData")); + byte[] data = AESUtil.decrypt(data_, ByteUtil.hexStringToBytes(key)); + + String decryptResult = new String(data, StandardCharsets.UTF_8); + resMap.put("data", decryptResult); + resMap.remove("businessData"); + } + log.info("【银盛进件】解密后的完整参数为:{}", JSON.toJSONString(resMap)); + + return JSON.toJSONString(resMap); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + public static String applymentRequest(ReqMethod.Method method, YspayIsvParams isvParams, JSONObject bizContent) { + return applymentRequest(method, isvParams, bizContent, null); + } + + /** + * 发起进件请求 + * + * @param method + * @param isvParams + * @param bizContent + * @param imgFileByteArray 要上传的文件 + * @return + */ + public static String applymentRequest(ReqMethod.Method method, YspayIsvParams isvParams, JSONObject bizContent, byte[] imgFileByteArray) { + String url = ReqMethod.getUrl(method); + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + // 接口名称 + reqParams.put("method", url); + // 请求的时间 + reqParams.put("timeStamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求流水号 + reqParams.put("reqId", DateKit.currentTimeMillis() + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN)); + // 通道服务商号 + reqParams.put("certId", isvParams.getPartnerId()); + // 版本号 + reqParams.put("version", method.getVersion()); + + /** 2、生成对业务参数加密的密钥*/ + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 16; i++) { + sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); + } + String key = ByteUtil.toHexString(sb.toString()); + + /** 3、使用银盛公钥对密钥key进行加密,得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/ + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String publicKeyFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + String check = null; + + BufferedInputStream inputStream = FileUtil.getInputStream(publicKeyFilePath); + byte[] publicKeyEncoded = SecureUtil.readX509Certificate(inputStream).getPublicKey().getEncoded(); + SM2 sm2 = null; + RSA rsa = null; + if ("SM".equals(isvParams.getSignType())) { + sm2 = SmUtil.sm2(null, publicKeyEncoded); + check = sm2.encryptBase64(publicKeyFilePath, KeyType.PublicKey); + } else if ("RSA".equals(isvParams.getSignType())) { + rsa = SecureUtil.rsa(null, publicKeyEncoded); + check = rsa.encryptBase64(ByteUtil.hexStringToBytes(key), KeyType.PublicKey); + } + + //加密后的密钥 + reqParams.put("check", check); + + /** 4、封装业务参数 */ + + /** 5、使用生成的密钥key对业务参数进行加密,并将加密后的业务参数放入请求参数bizContent中*/ + byte[] bte = AESUtil.encrypt(JSON.toJSONBytes(bizContent, SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key)); + reqParams.put("bizContent", org.apache.tomcat.util.codec.binary.Base64.encodeBase64String(bte)); + + + /** 6、将请求参数进行sort排序,生成拼接的字符床,并使用接入方私钥对请求参数进行加签,并将加签的值存入请求参数sign中*/ + String sign = getSign(isvParams, reqParams); + reqParams.put("sign", sign); + + /** 7、发送http请求获取返回结果 */ + log.info("【银盛进件】请求地址:{},发起请求:{},加密前bizContent:{}", url, reqParams, bizContent); + + HttpRequest httpRequest; + if (imgFileByteArray == null) { + httpRequest = HttpRequest.post(url) + .header("Content-type", "application/json") + .timeout(20000) + .charset("UTF-8") + .body(reqParams.toJSONString()); + } else { + httpRequest = HttpUtil.createPost(url) + .form("file", imgFileByteArray, "1.png") + .form(JSON.toJavaObject(reqParams, Map.class)); + } + + @Cleanup HttpResponse httpResponse = httpRequest.execute(); + String result = httpResponse.body(); + + byte[] res = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(result); + Map resMap = (Map) JSONObject.parse(new String(res, StandardCharsets.UTF_8)); + log.info("【银盛接口】响应结果:{}", JSON.toJSONString(resMap)); + + /** 8、对结果进行解密,并使用银盛公钥验签*/ + if (StringUtils.isNotBlank(resMap.get("sign"))) { + if ("SM".equals(isvParams.getSignType())) { + byte[] srcData = GMSignUtils.getSignDataStr1(resMap).getBytes("UTF-8"); + boolean validateSignResult1 = sm2.verify(srcData, Base64.decodeBase64(resMap.get("sign").getBytes(StandardCharsets.UTF_8))); + if (!validateSignResult1) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } else if ("RSA".equals(isvParams.getSignType())) { + byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes(StandardCharsets.UTF_8); + Sign sign2 = cn.hutool.crypto.SignUtil.sign(SignAlgorithm.SHA256withRSA, null, publicKeyEncoded); + boolean validateSignResult1 = sign2.verify(srcData, Base64.decodeBase64(resMap.get("sign").getBytes(StandardCharsets.UTF_8))); + if (!validateSignResult1) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } + } else { + throw new BizException("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}" + resMap.get("msg")); + } + + /** 9、针对自己的业务,根据返回的结果的code 和 subCode 做接入方的业务处理*/ + if (!APPLY_CODE.equals(resMap.get("code"))) { + throw new BizException(StringUtils.isBlank(resMap.get("msg")) ? "请求响应失败" : resMap.get("msg")); + } + if (!APPLY_SUB_CODE.equals(resMap.get("subCode"))) { + if ("B510091".equals(resMap.get("subCode"))) { + throw new BizException(ApiCodeEnum.YS_ARTIFICIAL_AUDIT_CODE); + } + + throw new BizException(StringUtils.isBlank(resMap.get("subMsg")) ? "业务响应失败" : resMap.get("subMsg")); + } + + /** 10、使用上面生成的加密密钥key,解密返回的业务参数*/ + if (StringUtils.isNotBlank(resMap.get("businessData"))) { + byte[] data_ = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(resMap.get("businessData")); + byte[] data = AESUtil.decrypt(data_, ByteUtil.hexStringToBytes(key)); + + String decryptResult = new String(data, StandardCharsets.UTF_8); + resMap.put("data", decryptResult); + resMap.remove("businessData"); + } + log.info("【银盛进件】解密后的完整参数为:{}", JSON.toJSONString(resMap)); + + return JSON.toJSONString(resMap); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 图片上传接口 + * + * @param sysFlowId + * @param isvParams + * @param imgUrl + * @param picType + * @return + */ + public static JSONObject uploadRequest(String sysFlowId, YspayIsvParams isvParams, String imgUrl, String picType) { + + try { + if (StringUtils.isEmpty(imgUrl)) { + return null; + } + + JSONObject bizContent = new JSONObject(); + + // meta媒体文件元素信息 + Map metaJSONObject = new HashMap<>(); + + // 下载文件 + byte[] imgFileByteArray = null; + try { + ByteArrayOutputStream baos = ImageUtils.compressNetPic(imgUrl, 2048 * 1024); + imgFileByteArray = baos.toByteArray(); + } catch (IORuntimeException e) { + log.info("银盛入网压缩图片异常, 图片链接为{}", imgUrl, e); + throw new BizException("银盛入网压缩图片失败, " + e.getMessage()); + } + + String sha256 = DigestUtils.sha256Hex(IoUtil.toStream(imgFileByteArray)); + + metaJSONObject.put("sha256", sha256); + // 图片类型, A001-营业执照 A002-法人身份证正面(头像面) A003-法人身份证反面(国徽面) A004-结算账户正面(卡号面) A005-结算账户反面 A006-商户门头照片 A007-内景照片 A008-收银台照片 A009-手持身份证合影照片 A010-收单协议盖章页 A011-开户许可证 A012-收单协议首页 A013-非法人身份证头像面 A014-非法人身份证国徽面 B001-租赁合同 第一页 B002-租赁合同 第二页 B003-租赁合同 第三页 B004-法人/非法人手持授权书 B005-法人/非法人结算授权书 B006-租赁面积图片 B007-经营业务图片 B008-其他1 B009-其他2 + metaJSONObject.put("picType", picType); + // 图片名称 + metaJSONObject.put("picNm", IdUtil.fastSimpleUUID()); + // 流水号 + metaJSONObject.put("sysFlowId", sysFlowId); + //设置媒体元素信息 + bizContent.put("meta", metaJSONObject); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/file/smsc/upload", "file.smsc.upload", isvParams, bizContent, imgFileByteArray); + + JSONObject responseJson = JSON.parseObject(resultStr); + JSONObject dataJson = responseJson.getJSONObject("data"); + // String note = dataJson.getString("note"); + + JSONObject respJson = new JSONObject(); + /*respJson.put("note", note); + respJson.put("picType", picType);*/ + return respJson; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 图片上传接口 + * + * @param changeFlowId + * @param isvParams + * @param imgUrl + * @param picType + * @return + */ + public static JSONObject uploadEditRequest(String changeFlowId, YspayIsvParams isvParams, String imgUrl, String picType) { + + try { + if (StringUtils.isEmpty(imgUrl)) { + return null; + } + + JSONObject bizContent = new JSONObject(); + + // meta媒体文件元素信息 + Map metaJSONObject = new HashMap<>(); + + // 下载文件 + byte[] imgFileByteArray = HttpUtil.downloadBytes(imgUrl); + String sha256 = DigestUtils.sha256Hex(IoUtil.toStream(imgFileByteArray)); + + metaJSONObject.put("sha256", sha256); + // 图片类型, A001-营业执照 A002-法人身份证正面(头像面) A003-法人身份证反面(国徽面) A004-结算账户正面(卡号面) A005-结算账户反面 A006-商户门头照片 A007-内景照片 A008-收银台照片 A009-手持身份证合影照片 A010-收单协议盖章页 A011-开户许可证 A012-收单协议首页 A013-非法人身份证头像面 A014-非法人身份证国徽面 B001-租赁合同 第一页 B002-租赁合同 第二页 B003-租赁合同 第三页 B004-法人/非法人手持授权书 B005-法人/非法人结算授权书 B006-租赁面积图片 B007-经营业务图片 B008-其他1 B009-其他2 + metaJSONObject.put("picType", picType); + // 图片名称 + metaJSONObject.put("picNm", IdUtil.fastSimpleUUID()); + // 流水号 + metaJSONObject.put("changeFlowId", changeFlowId); + //设置媒体元素信息 + bizContent.put("meta", metaJSONObject); + + // 发送请求 + String resultStr = YspayKit.applymentRequest("/openapi/file/smsc/uploadChangePic", "file.smsc.uploadChangePic", isvParams, bizContent, imgFileByteArray); + + JSONObject responseJson = JSON.parseObject(resultStr); + JSONObject dataJson = responseJson.getJSONObject("data"); + // String note = dataJson.getString("note"); + + JSONObject respJson = new JSONObject(); + /*respJson.put("note", note); + respJson.put("picType", picType);*/ + return respJson; + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 银盛V3接口 + * + * @param method + * @param bizContent + * @return + */ + public static JSONObject reqV3(ReqMethod.Method method, YspayIsvParams isvParams, JSONObject bizContent) { + try { + // 公共参数 + JSONObject reqParams = new JSONObject(); + String key = initV3(method, isvParams, bizContent, reqParams); + /** 7、发送http请求获取返回结果 */ + log.info("【银盛进件】请求地址:{},请求参数:{},业务参数:{}", ReqMethod.getUrl(method), reqParams, bizContent); + String result = HttpRequest.post(ReqMethod.getUrl(method)) + .header("Content-type", "application/json") + .timeout(20000) + .charset("UTF-8") + .body(reqParams.toJSONString()) + .execute() + .body(); + return initResult(result, isvParams, key); + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 通用处理请求返回结果 + * + * @param result + * @param isvParams + * @param key + * @return + */ + // 统一初始化返回参数 + private static JSONObject initResult(String result, YspayIsvParams isvParams, String key) { + try { + byte[] res = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(result); + Map resMap = (Map) JSONObject.parse(new String(res, StandardCharsets.UTF_8)); + log.info("【银盛进件】响应结果:{}", JSON.toJSONString(resMap)); + /** 8、对结果进行解密,并使用银盛公钥验签*/ + if (StringUtils.isNotBlank(resMap.get("sign"))) { + if ("SM".equals(isvParams.getSignType())) { + byte[] srcData = GMSignUtils.getSignDataStr1(resMap).getBytes("UTF-8"); + GMCertInfo verifyCertInfo = GMSignUtils.getVerifyCertInfo(isvParams.getPublicKeyFile()); + boolean validateSignResult = GMSignUtils.verifyMsgSignSM2(verifyCertInfo, org.apache.tomcat.util.codec.binary.Base64.decodeBase64(resMap.get("sign")), srcData); + if (!validateSignResult) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } else if ("RSA".equals(isvParams.getSignType())) { + byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes(StandardCharsets.UTF_8); + boolean validateSignResult = RSA256Util.validateSign(isvParams.getPublicKeyFile(), org.apache.tomcat.util.codec.binary.Base64.decodeBase64(resMap.get("sign")), srcData); + if (!validateSignResult) { + log.info("【银盛进件】响应验签失败"); + throw new BizException("验签失败"); + } + } + if (!APPLY_CODE.equals(resMap.get("code"))) { + throw new BizException(StringUtils.isBlank(resMap.get("msg")) ? "请求响应失败" : resMap.get("msg")); + } + if (!APPLY_SUB_CODE.equals(resMap.get("subCode"))) { + throw new BizException(StringUtils.isBlank(resMap.get("subMsg")) ? "业务响应失败" : resMap.get("subMsg")); + } + + /** 10、使用上面生成的加密密钥key,解密返回的业务参数*/ + if (StringUtils.isNotBlank(resMap.get("businessData"))) { + byte[] data_ = org.apache.tomcat.util.codec.binary.Base64.decodeBase64(resMap.get("businessData")); + byte[] data = AESUtil.decrypt(data_, ByteUtil.hexStringToBytes(key)); + String decryptResult = new String(data, StandardCharsets.UTF_8); + log.info("【银盛】响应参数解析结果:{}", decryptResult); + return JSON.parseObject(decryptResult); + } + return null; + } else { + throw new BizException("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}" + resMap.get("msg")); + } + } catch (Exception e) { + throw new BizException(e.getMessage()); + } + } + + /** + * 初始化公共参数 + * + * @param method + * @param isvParams + * @param bizContent + * @param ifCode + * @param reqParams + * @return + */ + public static String initV3(ReqMethod.Method method, YspayIsvParams isvParams, JSONObject bizContent, JSONObject reqParams) { + try { + // 接口名称 + reqParams.put("method", method.getMethod()); + // 请求的时间 + reqParams.put("timeStamp", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN)); + // 编码格式 + reqParams.put("charset", "utf-8"); + // 请求流水号 + reqParams.put("reqId", DateKit.currentTimeMillis() + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN)); + // 通道服务商号 + reqParams.put("certId", isvParams.getPartnerId()); + // 版本号 + reqParams.put("version", method.getVersion()); + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 16; i++) { + sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length()))); + } + String key = ByteUtil.toHexString(sb.toString()); + + /** 3、使用银盛公钥对密钥key进行加密,得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/ + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + String publicKeyFilePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile()); + String check = null; + if ("SM".equals(isvParams.getSignType())) { + check = GMSignUtils.encryptData(publicKeyFilePath, key); + } else if ("RSA".equals(isvParams.getSignType())) { + byte[] byte1 = RSA256Util.encrypt(publicKeyFilePath, ByteUtil.hexStringToBytes(key)); + check = org.apache.tomcat.util.codec.binary.Base64.encodeBase64String(byte1); + } + //加密后的密钥 + reqParams.put("check", check); + /** 4、封装业务参数 */ + /** 5、使用生成的密钥key对业务参数进行加密,并将加密后的业务参数放入请求参数bizContent中*/ + byte[] bte = AESUtil.encrypt(JSON.toJSONBytes(bizContent, SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key)); + reqParams.put("bizContent", org.apache.tomcat.util.codec.binary.Base64.encodeBase64String(bte)); + String sign = getSign(isvParams, reqParams); + reqParams.put("sign", sign); + return key; + } catch (Exception e) { + throw new BizException("银盛签名异常"); + } + } + + public static void main(String[] args) { + String aa = "{\"bizContent\":\"hLAQku6C1EPL1nKuo4WUztUbTYET4tNTJ03Nda9aX52n6Aa1pWFi+Q0hL5AuGgDaZrps4a4795UWvooTMWPhvcbNWW4I161Rq/kGMEYxv+78JWKa4TbSZZclkXwsv343J48FFcE5gIuM7s46tLG6ag==\",\"certId\":\"826521773920170\",\"charset\":\"utf-8\",\"check\":\"cUZ3neRqOJlvVxaIRWQlrsH8GgKVsXRmYHv6Xa/n5rSzIx/0SyONAi5IxHm0pNqb5WfGYS+A5sFs6lFqREvevnSmeWpnOsSaaGcUYbZu8AMchNeOluJzH/j52iqH+98tl9IlOABtZk9IllFIbiKHhWSzONR2KSBcpU58MbEpJaA=\",\"method\":\"report.scan.union.appIdAddOrUpdate\",\"reqId\":\"SYB_5vpw231204151549\",\"sign\":\"QhrmcOJKjBvkFADf6K+6WjzQR0WG1iXgmUkRKoFqF1sBFuTDhVfBqda/FSmEZFA4bEJbkazeMF7NruGBzktJUyMsCruS9O5dfW/QSZ46iUVvo0iYS+2DeAfv53SlEnjXMTZaSpBr+TeF/9WhDMfBo+siWdutOjOE6lERA/05lxnqi7fftZ9Usikl+ODF97iDfg0if+CpQ3eKq+o31h1kd2hHTtiL/W7BVs0E313IqAx41VXt2aH0mUcOLuvQOKQ01ux++0gM0Ooh+jreHUiPgT9XoZI6OYFV78QA6aeTvmW8ABVXA3k2Xr0NVvvj0zpOzSpt+c7dUktBAGk0YwfVAA==\",\"timeStamp\":\"2023-12-04 15:15:49\",\"version\":\"1.0\"}"; + JSONObject data = JSON.parseObject(aa); + String check = data.getString("check"); + String pubKeyPath = "D:\\home\\jeepay\\upload\\private\\cert\\82483d5d-fab4-42fd-a56e-4febb43c1316.cer"; + + System.out.println(check); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayChannelNoticeService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayChannelNoticeService.java new file mode 100644 index 0000000..1fb0493 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayChannelNoticeService.java @@ -0,0 +1,128 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.internal.util.AlipaySignature; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.AccountOperate; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ResponseException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.db.entity.AccountFundInfo; +import com.jeequan.jeepay.db.entity.AccountInfo; +import com.jeequan.jeepay.service.impl.AccountInfoService; +import com.jeequan.jeepay.thirdparty.channel.AbstractChannelNoticeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/* +* 支付宝 回调接口实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:20 +*/ +@Service +@Slf4j +public class ZftpayChannelNoticeService extends AbstractChannelNoticeService { + + @Autowired + private AccountInfoService accountService; + + @Override + public String getIfCode() { + return CS.IF_CODE.ZFTPAY; + } + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) { + + try { + JSONObject params = getReqParamJSON(); + String payOrderId = params.getString("out_trade_no"); + return MutablePair.of(payOrderId, params); + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + + + @Override + public ChannelRetMsg doNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) { + try { + //配置参数获取 + Byte useCert = null; + String alipaySignType, alipayPublicCert, alipayPublicKey = null; + // 获取支付参数 + ZftpayIsvParams alipayParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode()); + useCert = alipayParams.getUseCert(); + alipaySignType = alipayParams.getSignType(); + alipayPublicCert = alipayParams.getAlipayPublicCert(); + alipayPublicKey = alipayParams.getAlipayPublicKey(); + // 获取请求参数 + JSONObject jsonParams = (JSONObject) params; + boolean verifyResult; + if(useCert != null && useCert == CS.YES){ //证书方式 + verifyResult = AlipaySignature.rsaCertCheckV1(jsonParams.toJavaObject(Map.class), getCertFilePath(alipayPublicCert), + AlipayConfig.CHARSET, alipaySignType); + + }else{ + verifyResult = AlipaySignature.rsaCheckV1(jsonParams.toJavaObject(Map.class), alipayPublicKey, AlipayConfig.CHARSET, alipaySignType); + } + + //验签失败 + if(!verifyResult){ + throw ResponseException.buildText("ERROR"); + } + //验签成功后判断上游订单状态 + ResponseEntity okResponse = textResp("SUCCESS"); + ChannelRetMsg result = new ChannelRetMsg(); + result.setChannelBizData(jsonParams); + result.setChannelOrderId(jsonParams.getString("trade_no")); //渠道订单号 + result.setPlatformOrderNo(jsonParams.getString("trade_no")); + result.setPlatformMchOrderNo(payOrder.getPayOrderId()); + result.setChannelUserId(jsonParams.getString("buyer_id")); //支付用户ID + result.setResponseEntity(okResponse); //响应数据 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + if("TRADE_SUCCESS".equals(jsonParams.getString("trade_status"))){ + //如果支付成功 消减手续费账户余额 + changeFeeAccount(payOrder); + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else if("TRADE_CLOSED".equals(jsonParams.getString("trade_status"))){ + result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } + return result; + } catch (Exception e) { + log.error("error", e); + throw ResponseException.buildText("ERROR"); + } + } + + /** + * 扣减手续费账户余额 + * @param order + */ + public void changeFeeAccount(PayOrder order) { + try { + AccountInfo account = accountService.getAccountInfo(order.getMchNo(), AccountInfo.Type.SERVICE_CHARGE.getType()); + if(account != null){ + AccountOperate operate = new AccountOperate(account.getAccountNo(),order.getAmount(),AccountFundInfo.ChangeType.DEDUCT.getValue(), AccountFundInfo.ChangeMethod.ZFT.getValue(), order.getPayOrderId(),"直付通交易手续费扣除"); + operate.setFinalAmt(order.getMchOrderFeeAmount()); + operate.setIsUpdateAccount(true); + accountService.upAccount(operate); + } + }catch (Exception e){ + log.error("手续费账户扣除异常,订单号:{},异常信息:{}",order.getPayOrderId(),e.getMessage()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayDivisionService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayDivisionService.java new file mode 100644 index 0000000..8d604b0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayDivisionService.java @@ -0,0 +1,141 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.domain.AlipayTradeOrderOnsettleQueryModel; +import com.alipay.api.domain.AlipayTradeOrderSettleModel; +import com.alipay.api.domain.OpenApiRoyaltyDetailInfoPojo; +import com.alipay.api.request.AlipayTradeOrderOnsettleQueryRequest; +import com.alipay.api.request.AlipayTradeOrderSettleRequest; +import com.alipay.api.response.AlipayTradeOrderOnsettleQueryResponse; +import com.alipay.api.response.AlipayTradeOrderSettleResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.thirdparty.channel.AbstractDivisionService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 直付通分账接口 + * @author crystal + * @date 2024/04/18 18:45 + */ +@Slf4j +@Service +public class ZftpayDivisionService extends AbstractDivisionService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.ZFTPAY; + } + + @Override + public boolean isSupport() { + return false; + } + + @Override + public ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + String logPrefix = "[直付通添加分账]"; + try { + String newDivisionReceiverSubMchId = mchDivisionReceiver.getAccNo(); + log.info("{}, 接收人账号{}", logPrefix, newDivisionReceiverSubMchId); + return ChannelRetMsg.confirmSuccess(null).setChannelAttach(newDivisionReceiverSubMchId); + } catch (ChannelException e) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + } catch (Exception e) { + log.error("{}异常", logPrefix, e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg singleDivision(PayOrder payOrder, List recordList, MchAppConfigContext mchAppConfigContext) { + try { + AlipayClient alipayClient = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient(); + AlipayTradeOrderSettleRequest request = new AlipayTradeOrderSettleRequest(); + AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel(); + // 设置结算请求流水号 + model.setOutRequestNo(SeqKit.genDivisionBatchId()); + // 设置支付宝订单号 + model.setTradeNo(payOrder.getChannelOrderNo()); + List royaltyParameters = new ArrayList<>(); + recordList.forEach(item -> { + OpenApiRoyaltyDetailInfoPojo royaltyParameters0 = new OpenApiRoyaltyDetailInfoPojo(); + royaltyParameters0.setRoyaltyType("transfer"); + royaltyParameters0.setTransInType("userId"); + royaltyParameters0.setTransIn(item.getChannelAccNo()); + royaltyParameters0.setAmount(AmountUtil.convertCent2Dollar(item.getCalDivisionAmount())); + royaltyParameters0.setDesc(StringUtils.isNotEmpty(item.getRemark()) ? item.getRemark() : "订单分账"); + royaltyParameters.add(royaltyParameters0); + }); + model.setRoyaltyParameters(royaltyParameters); + request.setBizModel(model); + AlipayTradeOrderSettleResponse response = alipayClient.execute(request); + if(response.isSuccess()){ + return ChannelRetMsg.confirmSuccess(response.getSettleNo()); + } + return ChannelRetMsg.confirmFail().setChannelErrCode(response.getSubCode()).setChannelErrMsg(response.getSubMsg()); + } catch (ChannelException e) { + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrCode(e.getChannelRetMsg().getChannelErrCode()); + channelRetMsg.setChannelErrMsg(e.getChannelRetMsg().getChannelErrMsg()); + return channelRetMsg; + } catch (Exception e) { + log.error("直付通分账异常", e); + ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail(); + channelRetMsg.setChannelErrMsg(e.getMessage()); + return channelRetMsg; + } + } + + @Override + public ChannelRetMsg divisionRefund(PayOrderDivisionRecord payOrderDivisionRecord, PayOrderDivisionRefundRecord payOrderDivisionRefundRecord, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) { + return null; + } + + @Override + public Long queryBalanceAmount(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext) { + AlipayClient alipayClient = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient(); + AlipayTradeOrderOnsettleQueryRequest request = new AlipayTradeOrderOnsettleQueryRequest(); + AlipayTradeOrderOnsettleQueryModel model = new AlipayTradeOrderOnsettleQueryModel(); + //TODO 这里有问题 + model.setTradeNo(mchDivisionReceiver.getChannelAccNo()); + request.setBizModel(model); + try { + AlipayTradeOrderOnsettleQueryResponse response = alipayClient.execute(request); + if(response.isSuccess()){ + return AmountUtil.convertDollar2CentLong(response.getUnsettledAmount()); + } else { + throw new ParamException(response.getSubMsg()); + } + } catch (AlipayApiException e) { + throw new ParamException(e.getErrMsg()); + } + } + + @Override + public ChannelRetMsg cashout(MchDivisionReceiver mchDivisionReceiver, Long amount, MchAppConfigContext mchAppConfigContext) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayGetApplymentDataService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayGetApplymentDataService.java new file mode 100644 index 0000000..61a0626 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayGetApplymentDataService.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IGetApplymentDataService; +import com.jeequan.jeepay.db.entity.BankBranchZft; +import com.jeequan.jeepay.service.impl.BankBranchZftService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * TODO + * + * @author deng + * @since 2024/4/10 + */ +@Service +public class ZftpayGetApplymentDataService implements IGetApplymentDataService { + + @Autowired + private BankBranchZftService bankBranchZftService; + + public List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { + List list = bankBranchZftService.lambdaQuery() + .eq(BankBranchZft::getCity, cityCode) + .like(!ObjUtil.isEmpty(branchName), BankBranchZft::getBranchName, branchName) + .last("limit 1000") + .list(); + + return list.stream().map( t -> ((JSONObject) JSON.toJSON(t))).collect(Collectors.toList()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..60ef14b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchApplymentNotifyService.java @@ -0,0 +1,160 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentNotifyService; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.db.entity.MchModifyApplymentEntity; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.service.impl.MchModifyApplymentService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.nio.charset.Charset; + +/** + * + * @author deng + * @since 2024/4/7 + */ +@Service +public class ZftpayIsvmchApplymentNotifyService implements IIsvmchApplymentNotifyService { + + @Autowired + private RequestKitBean requestKitBean; + + @Autowired + private MchApplymentService mchApplymentService; + + @Autowired + private MchModifyApplymentService mchModifyApplymentService; + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private MchInfoConverter mchInfoConverter; + + @Override + public MutablePair parseParams(HttpServletRequest request, String urlApplyId) { + JSONObject reqParamJSON = requestKitBean.getReqParamJSON(); + + JSONObject bizContent = reqParamJSON.getJSONObject("biz_content"); + String orderId = bizContent.getString("order_id"); + + com.jeequan.jeepay.db.entity.MchApplyment mchApplymentEntity = mchApplymentService.getByOrderId(orderId); + MchApplyment mchApplyment; + + ZftpayIsvParams isvParams; + if (mchApplymentEntity != null) { + // 商户进件 + mchApplyment = mchInfoConverter.toModel(mchApplymentEntity); + } else { + // 商户信息变更 + MchModifyApplymentEntity mchModifyApplymentEntity = mchModifyApplymentService.getByOrderId(orderId, CS.IF_CODE.ZFTPAY); + mchApplymentEntity = mchApplymentService.getById(mchModifyApplymentEntity.getApplyId()); + mchApplyment = mchInfoConverter.toModel(mchApplymentEntity); + } + + Assert.notNull(mchApplyment, "未获取到商户信息"); + + isvParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + Charset charset = Charset.forName(reqParamJSON.getString("charset")); + ZftpayKit.syncCheckSign(reqParamJSON, isvParams, charset); + + return new MutablePair<>(mchApplyment.getApplyId(), reqParamJSON); + } + + @Override + public MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment) { + JSONObject callbackData = (JSONObject) params; + String msgMethod = callbackData.getString("msg_method"); + + JSONObject bizContent = callbackData.getJSONObject("biz_content"); + String orderId = bizContent.getString("order_id"); + + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + result.setState(mchApplyment.getState()); + + com.jeequan.jeepay.db.entity.MchApplyment mchApplymentEntity = mchApplymentService.getByOrderId(orderId); + if (mchApplymentEntity == null) { + // 商户信息变更 + return processMchModifyApplymentCallback(orderId, msgMethod, bizContent); + } else { + // 进件回调 + return processMchApplymentCallback(result, msgMethod, bizContent); + } + } + + private MutablePair processMchApplymentCallback(MchApplyment result, String msgMethod, JSONObject bizContent) { + // ... 进件回调处理逻辑 ... + result.setChannelVar1(bizContent.toJSONString()); + + if ("ant.merchant.expand.indirect.zft.passed".equals(msgMethod)) { + // 进件通过 + String smid = bizContent.getString("smid"); + String memo = bizContent.getString("memo"); + result.setState(MchApplyment.STATE_SUCCESS); + result.setChannelMchNo(smid); + result.setRemark("[" + memo + "]"); + + return new MutablePair<>(result, retOk(null)); + } + + if ("ant.merchant.expand.indirect.zft.rejected".equals(msgMethod)) { + // 进件驳回 + String reason = bizContent.getString("reason"); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + reason + "]"); + return new MutablePair<>(result, retOk(null)); + } + + return null; + } + + private MutablePair processMchModifyApplymentCallback(String orderId, String msgMethod, JSONObject bizContent) { + // ... 商户信息变更回调处理逻辑 ... + MchModifyApplymentEntity modifyResult = new MchModifyApplymentEntity(); + + MchModifyApplymentEntity mchModifyApplymentEntity = mchModifyApplymentService.getByOrderId(orderId, CS.IF_CODE.ZFTPAY); + modifyResult.setModifyApplyId(mchModifyApplymentEntity.getModifyApplyId()); + modifyResult.setChannelVar1(bizContent.toJSONString()); + + if ("ant.merchant.expand.indirect.zft.passed".equals(msgMethod)) { + // 变更成功 + String smid = bizContent.getString("smid"); + String memo = bizContent.getString("memo"); + modifyResult.setState(MchApplyment.STATE_SUCCESS); + modifyResult.setChannelMchNo(smid); + modifyResult.setRemark("[" + memo + "]"); + + mchModifyApplymentService.localModify(mchInfoConverter.toModel(mchModifyApplymentEntity)); + return new MutablePair<>(null, retOk(null)); + } + + if ("ant.merchant.expand.indirect.zft.rejected".equals(msgMethod)) { + // 变更失败 + String reason = bizContent.getString("reason"); + modifyResult.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + modifyResult.setApplyErrorInfo("[" + reason + "]"); + return new MutablePair<>(null, retOk(null)); + } + + return null; + } + + @Override + public ResponseEntity retOk(Object params) { + return ResponseEntity.ok("success"); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchModifyApplymentService.java new file mode 100644 index 0000000..81990ef --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayIsvmchModifyApplymentService.java @@ -0,0 +1,234 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alipay.api.domain.*; +import com.alipay.api.request.AntMerchantExpandIndirectZftModifyRequest; +import com.alipay.api.request.AntMerchantExpandIndirectZftorderQueryRequest; +import com.alipay.api.response.AntMerchantExpandIndirectZftModifyResponse; +import com.alipay.api.response.AntMerchantExpandIndirectZftorderQueryResponse; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchModifyApplyment; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchModifyApplymentService; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.ZftpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.db.entity.BankBranchZft; +import com.jeequan.jeepay.service.impl.BankBranchZftService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import java.util.Collections; + +/** + * TODO + * + * @author deng + * @since 2024/4/17 + */ +@Service +public class ZftpayIsvmchModifyApplymentService implements IIsvmchModifyApplymentService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private BankBranchZftService bankBranchZftService; + + @Override + public MutablePair localModifyBase(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + ZftpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, ZftpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setMchShortName(mchModifyData.getMchShortName()); + resultMchApplyment.setMchShortName(mchModifyData.getMchShortName()); + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifySettlement(MutablePair mchDataPair) { + MchModifyApplyment resultModifyApplyment = new MchModifyApplyment(); + MchApplyment resultMchApplyment = new MchApplyment(); + + MchModifyApplyment mchModifyApplyment = mchDataPair.getKey(); + resultModifyApplyment.setModifyApplyId(mchModifyApplyment.getModifyApplyId()); + resultModifyApplyment.setState(MchApplyment.STATE_SUCCESS); + MchApplyment mchApplyment = mchDataPair.getValue(); + resultMchApplyment.setApplyId(mchApplyment.getApplyId()); + + String applyDetailInfo = mchModifyApplyment.getApplyDetailInfo(); + MchModifyApplymentModel mchModifyData = JSON.parseObject(applyDetailInfo, MchModifyApplymentModel.class); + + String originApplyDetailInfo = mchApplyment.getApplyDetailInfo(); + ZftpayApplymentInfo originMchModifyData = JSON.parseObject(originApplyDetailInfo, ZftpayApplymentInfo.class); + resultMchApplyment.setApplyDetailInfo(JSON.toJSONString(originMchModifyData)); + + originMchModifyData.setDefaultSettleType(mchModifyData.getDefaultSettleType()); + + if (!ObjUtil.isEmpty(mchModifyData.getDefaultSettleType())) { + // 支付宝支付 + originMchModifyData.setAlipayLogonId(mchModifyData.getAlipayLogonId()); + } else { + originMchModifyData.setSettAccountLicenseImg(mchModifyData.getSettAccountLicenseImg()); + originMchModifyData.setSettAccountName(mchModifyData.getSettAccountName()); + originMchModifyData.setSettAccountNo(mchModifyData.getSettAccountNo()); + originMchModifyData.setSettAccountBankBranchAreaCode(mchModifyData.getSettAccountBankBranchAreaCode()); + originMchModifyData.setSettAccountBankBranchCode(mchModifyData.getBankSubCode()); + originMchModifyData.setSettAccountBankName(mchModifyData.getSettAccountBankName()); + } + + return new MutablePair<>(resultModifyApplyment, resultMchApplyment); + } + + @Override + public MutablePair localModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifyBase(MutablePair mchDataPair) { + MchApplyment mchApplyment = mchDataPair.right; + MchModifyApplyment modifyApplyment = mchDataPair.left; + MchModifyApplyment result = new MchModifyApplyment(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + ZftpayIsvParams isvParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + MchModifyApplymentModel mchModifyApplymentModel = JSON.parseObject(modifyApplyment.getApplyDetailInfo(), MchModifyApplymentModel.class); + String mchShortName = mchModifyApplymentModel.getMchShortName(); + + AntMerchantExpandIndirectZftModifyModel zftModifyModel = new AntMerchantExpandIndirectZftModifyModel(); + zftModifyModel.setAliasName(mchShortName); + zftModifyModel.setSmid(mchApplyment.getChannelMchNo()); + AntMerchantExpandIndirectZftModifyRequest request = new AntMerchantExpandIndirectZftModifyRequest(); + request.setBizModel(zftModifyModel); + + AntMerchantExpandIndirectZftModifyResponse response = ZftpayKit.req(isvParams, request); + String orderId = response.getOrderId(); + + result.setChannelMchNo(orderId); + result.setState(MchApplyment.STATE_AUDITING); + + return new MutablePair<>(result, null); + } + + @Override + public MutablePair syncChannelModifySettlement(MutablePair mchDataPair) { + MchApplyment mchApplyment = mchDataPair.right; + MchModifyApplyment modifyApplyment = mchDataPair.left; + MchModifyApplyment result = new MchModifyApplyment(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + + ZftpayIsvParams isvParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + MchModifyApplymentModel mchModifyApplymentModel = JSON.parseObject(modifyApplyment.getApplyDetailInfo(), MchModifyApplymentModel.class); + String mchShortName = mchModifyApplymentModel.getMchShortName(); + + AntMerchantExpandIndirectZftModifyModel zftModifyModel = new AntMerchantExpandIndirectZftModifyModel(); + AntMerchantExpandIndirectZftModifyRequest request = new AntMerchantExpandIndirectZftModifyRequest(); + request.setBizModel(zftModifyModel); + zftModifyModel.setSmid(mchApplyment.getChannelMchNo()); + + DefaultSettleRule defaultSettleRule = new DefaultSettleRule(); + zftModifyModel.setDefaultSettleRule(defaultSettleRule); + defaultSettleRule.setDefaultSettleType(mchModifyApplymentModel.getDefaultSettleType()); + + if ("bankCard".equals(mchModifyApplymentModel.getDefaultSettleType())) { + // 银行卡支付 + SettleCardInfo bizCard = new SettleCardInfo(); + bizCard.setAccountNo(mchModifyApplymentModel.getSettAccountNo()); + + Assert.notNull(mchModifyApplymentModel.getBankSubCode(), "支行联行号不能为空"); + BankBranchZft branchZft = bankBranchZftService.lambdaQuery() + .eq(BankBranchZft::getBranchNo, mchModifyApplymentModel.getBankSubCode()) + .one(); + + bizCard.setAccountInstName(branchZft.getBankName()); + bizCard.setAccountInstId(branchZft.getBankAbbr()); + bizCard.setBankCode(branchZft.getBranchNo()); + bizCard.setAccountNo(mchModifyApplymentModel.getSettAccountNo()); + defaultSettleRule.setDefaultSettleTarget(mchModifyApplymentModel.getSettAccountNo()); + + zftModifyModel.setBizCards(Collections.singletonList(bizCard)); + } else { + // 支付宝支付 + zftModifyModel.setAlipayLogonId(mchModifyApplymentModel.getAlipayLogonId()); + defaultSettleRule.setDefaultSettleTarget(mchModifyApplymentModel.getAlipayLogonId()); + } + + AntMerchantExpandIndirectZftModifyResponse response = ZftpayKit.req(isvParams, request); + String orderId = response.getOrderId(); + + result.setChannelMchNo(orderId); + result.setState(MchApplyment.STATE_AUDITING); + + return new MutablePair<>(result, null); + } + + @Override + public MutablePair syncChannelModifyRate(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair syncChannelModifySettlementType(MutablePair mchDataPair) { + return null; + } + + @Override + public MutablePair queryModifyResult(MutablePair mchDataPair) { + MchApplyment mchApplyment = mchDataPair.right; + MchModifyApplyment modifyApplyment = mchDataPair.left; + MchModifyApplyment result = new MchModifyApplyment(); + result.setModifyApplyId(modifyApplyment.getModifyApplyId()); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + + ZftpayIsvParams isvParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + + AntMerchantExpandIndirectZftorderQueryModel queryModel = new AntMerchantExpandIndirectZftorderQueryModel(); + AntMerchantExpandIndirectZftorderQueryRequest request = new AntMerchantExpandIndirectZftorderQueryRequest(); + queryModel.setOrderId(modifyApplyment.getApplyId()); + + AntMerchantExpandIndirectZftorderQueryResponse response = ZftpayKit.req(isvParams, request); + + for (ZftSubMerchantOrder order : response.getOrders()) { + if (order.getOrderId().equals(modifyApplyment.getApplyId())) { + if ("99".equals(order.getStatus())) { + // 成功 + switch (modifyApplyment.getModifyApplyType()) { + case MchModifyApplyment.MODIFY_TYPE_BASE: + return localModifyBase(mchDataPair); + case MchModifyApplyment.MODIFY_TYPE_SETTLEMENT: + return localModifySettlement(mchDataPair); + } + } + + if ("-1".equals(order.getStatus())) { + // 失败 + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + } + + break; + } + } + + return new MutablePair<>(result, mchApplyment); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayKit.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayKit.java new file mode 100644 index 0000000..365cfff --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayKit.java @@ -0,0 +1,203 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.resource.BytesResource; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import cn.hutool.http.ContentType; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.*; +import com.alipay.api.request.AntMerchantExpandIndirectZftCreateRequest; +import com.alipay.api.response.AntMerchantExpandIndirectZftCreateResponse; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.core.utils.ImageUtils; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.model.ReqEntity; +import com.jeequan.jeepay.thirdparty.channel.zftpay.model.ReqMethod; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import javax.xml.bind.DatatypeConverter; +import java.io.ByteArrayOutputStream; +import java.nio.charset.Charset; + +@Slf4j +public class ZftpayKit { + + public static final String SUCCESS_CODE = "10000"; + + public static JSONObject req(ZftpayIsvParams isvParams, JSONObject reqData) { + AlipayConfig alipayConfig = getAlipayConfig(isvParams); + + log.warn("请求业务参数:{}", reqData); + + AlipayClient alipayClient = null; + try { + alipayClient = new DefaultAlipayClient(alipayConfig); + } catch (AlipayApiException e) { + log.error("获取直付通配置信息异常", e); + throw new BizException("获取直付通配置信息异常"); + } + + AntMerchantExpandIndirectZftCreateRequest zftCreateRequest = new AntMerchantExpandIndirectZftCreateRequest(); + zftCreateRequest.setBizContent(reqData.toJSONString()); + + try { + AntMerchantExpandIndirectZftCreateResponse response = alipayClient.execute(zftCreateRequest); + + if (!response.isSuccess()) { + throw new BizException(response.getSubMsg()); + } + + return (JSONObject) JSON.toJSON(response); + } catch (Exception e) { + log.info("直付通进件请求异常", e); + throw new BizException(e.getMessage()); + } + } + + private static AlipayConfig getAlipayConfig(ZftpayIsvParams isvParams) { + AlipayConfig config = new AlipayConfig(); + config.setAlipayPublicKey(isvParams.getAlipayPublicKey()); + config.setPrivateKey(isvParams.getPrivateKey()); + config.setAppId(isvParams.getAppId()); + + return config; + } + + public static T req(ZftpayIsvParams isvParams, AlipayRequest request) { + AlipayConfig alipayConfig = getAlipayConfig(isvParams); + + log.info("直付通请求业务参数:{}", JSON.toJSONString(request.getBizModel())); + + AlipayClient alipayClient = null; + try { + alipayClient = new DefaultAlipayClient(alipayConfig); + } catch (AlipayApiException e) { + log.error("获取直付通配置信息异常", e); + throw new BizException("获取直付通配置信息异常"); + } + + try { + T response = alipayClient.execute(request); + + if (!response.isSuccess()) { + throw new BizException(response.getSubMsg()); + } + + log.info("直付通请求参数打印: {}", JSON.toJSONString(response)); + + return response; + } catch (Exception e) { + log.info("直付通进件请求异常", e); + throw new BizException(e.getMessage()); + } + } + + /** + * 异步验签 + */ + public static void syncCheckSign(JSONObject params, ZftpayIsvParams isvParams, Charset charset) { + + + //支付宝signType 不参与签名 TODO 回调通知签名和同步参数验签方式不一样 + String signContent; + params.remove("sign_type"); + String sign = ((String) params.remove("sign")); + if (ObjUtil.isEmpty(sign)) { + // 没有签名就不验 + return; + } + + signContent = JeepayKit.getStrSort(params); + log.info("待验签数据, {}", signContent); + Sign verify = SecureUtil.sign(SignAlgorithm.SHA256withRSA, isvParams.getPrivateKey(), isvParams.getAlipayPublicKey()); + boolean verifyResult = verify.verify(signContent.getBytes(charset), Base64.decode(sign)); + + Assert.isTrue(verifyResult, "验签失败"); + } + + /** + * 同步返回回调 + */ + public static void checkSign(String params, ZftpayIsvParams isvParams, String sign, Charset charset) { + if (ObjUtil.isEmpty(sign)) { + // 没有签名就不验 + return; + } + Sign verify = SecureUtil.sign(SignAlgorithm.SHA256withRSA, isvParams.getPrivateKey(), isvParams.getAlipayPublicKey()); + boolean verifyResult = verify.verify(params.getBytes(charset), Base64.decode(sign)); + + Assert.isTrue(verifyResult, "验签失败"); + } + + /** + * 发起请求 + * + * @param method + * @return + */ + public static JSONObject reqUpload(ZftpayIsvParams isvParams, ReqMethod method, String fileUrl) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + MultiValueMap param = new LinkedMultiValueMap<>(); + HttpEntity> httpEntity = new HttpEntity<>(param, httpHeaders); + + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, isvParams.getPrivateKey(), isvParams.getAlipayPublicKey()); + + ByteArrayOutputStream baos = ImageUtils.compressNetPic(fileUrl, 1024 * 1024 * 10); + BytesResource bytesResource = new BytesResource(baos.toByteArray(), "test.png"); + + HttpRequest httpRequest = HttpRequest.post(method.getUrl()) + .contentType(ContentType.MULTIPART.getValue()); + + ReqEntity request = new ReqEntity(method, isvParams.getAppId()); + request.setImage_type("png"); + + String encryptOriginData = JeepayKit.getStrSort(((JSONObject) JSON.toJSON(request))); + request.setSign(DatatypeConverter.printBase64Binary(sign.sign(encryptOriginData))); + + // {"msg":"Success","code":"10000","order_id":"2024041700502000000075319698"} + @Cleanup HttpResponse httpResponse = httpRequest.form("app_id", request.getApp_id()) + .form("method", request.getMethod()) + .form("format", request.getFormat()) + .form("charset", request.getCharset()) + .form("sign_type", request.getSign_type()) + .form("sign", request.getSign()) + .form("timestamp", request.getTimestamp()) + .form("version", request.getVersion()) + .form("image_content", bytesResource) + .form("image_type", "png") + .execute(); + + if (!httpResponse.isOk()) { + throw new BizException("直付通请求状态异常: statues = " + httpResponse.getStatus()); + } + + String respStr = httpResponse.body(); + log.info("直付通请求返回参数为:{}", respStr); + JSONObject respData = JSON.parseObject(respStr); + + Assert.notNull(respData, "直付通请求返回数据异常"); + JSONObject bizData = respData.getJSONObject(method.getResponseKey()); + String code = bizData.getString("code"); + + if (!SUCCESS_CODE.equals(code)) { + throw new BizException(bizData.getString("msg") + bizData.getString("msg")); + } + + return bizData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayMchApplymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayMchApplymentService.java new file mode 100644 index 0000000..3a49a64 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayMchApplymentService.java @@ -0,0 +1,378 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.io.resource.BytesResource; +import cn.hutool.core.util.ObjUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.*; +import com.alipay.api.request.AntMerchantExpandIndirectZftDeleteRequest; +import com.alipay.api.request.AntMerchantExpandIndirectZftorderQueryRequest; +import com.alipay.api.response.AntMerchantExpandIndirectZftDeleteResponse; +import com.alipay.api.response.AntMerchantExpandIndirectZftorderQueryResponse; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchApplymentService; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.ZftpayApplymentInfo; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.db.entity.BankBranchZft; +import com.jeequan.jeepay.service.impl.BankBranchZftService; +import com.jeequan.jeepay.service.impl.MchApplymentService; +import com.jeequan.jeepay.thirdparty.channel.zftpay.model.Const; +import com.jeequan.jeepay.thirdparty.channel.zftpay.model.ReqMethod; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service("zftpayMchApplymentService") +public class ZftpayMchApplymentService implements IIsvmchApplymentService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + @Autowired + private BankBranchZftService bankBranchZftService; + @Autowired + private MchApplymentService mchApplymentService; + + public AntMerchantExpandIndirectZftCreateModel getApplymentParams(MchApplyment mchApplyment) { + JSONObject result = new JSONObject(); + List files = new ArrayList<>(); + result.put("files", files); + ZftpayApplymentInfo applymentInfo = JSON.parseObject(mchApplyment.getApplyDetailInfo(), ZftpayApplymentInfo.class); + + ZftpayIsvParams isvParams = ((ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + + + if ("Y".equals(applymentInfo.getAuthSettle())) { + throw new BizException("直付通入网不支持非法人结算"); + } + + AntMerchantExpandIndirectZftCreateModel zftMerchInfo = new AntMerchantExpandIndirectZftCreateModel(); + + zftMerchInfo.setExternalId(mchApplyment.getApplyId()); + switch (applymentInfo.getMerchantType()) { + case MchApplyment.MERCHANT_TYPE_PERSONAL: + zftMerchInfo.setMerchantType("06"); + zftMerchInfo.setCertType("100"); + zftMerchInfo.setCertNo(applymentInfo.getIdcardNo()); + zftMerchInfo.setCertName(applymentInfo.getIdcardName()); + zftMerchInfo.setName(applymentInfo.getIdcardName()); + break; + case MchApplyment.MERCHANT_TYPE_INDIVIDUAL: + zftMerchInfo.setMerchantType("07"); + zftMerchInfo.setCertType("201"); + zftMerchInfo.setCertNo(applymentInfo.getLicenseNo()); + zftMerchInfo.setCertName(applymentInfo.getMchFullName()); + // 个体户使用法人名称 + zftMerchInfo.setName(applymentInfo.getIdcardName()); + break; + case MchApplyment.MERCHANT_TYPE_ENTERPRISE: + zftMerchInfo.setMerchantType("01"); + zftMerchInfo.setCertType("201"); + zftMerchInfo.setCertNo(applymentInfo.getLicenseNo()); + zftMerchInfo.setCertName(applymentInfo.getLicenseName()); + zftMerchInfo.setName(applymentInfo.getMchFullName()); + break; + default: + throw new BizException("未知商户类型"); + } + + Assert.notNull(applymentInfo.getIdcard1Img(), "身份证人像面图片不能为空"); + Assert.notNull(applymentInfo.getIdcard2Img(), "身份证国徽面图片不能为空"); + if (mchApplyment.getMerchantType() != MchApplyment.MERCHANT_TYPE_PERSONAL) { + Assert.notNull(applymentInfo.getLicenseImg(), "营业执照图片不能为空"); + zftMerchInfo.setCertImage(upload(isvParams, applymentInfo.getLicenseImg())); + zftMerchInfo.setLegalName(applymentInfo.getIdcardName()); + zftMerchInfo.setLegalCertNo(applymentInfo.getIdcardNo()); + + zftMerchInfo.setLegalCertFrontImage(upload(isvParams, applymentInfo.getIdcard1Img())); + Assert.notNull(applymentInfo.getIdcard2Img(), "身份证国徽面图片不能为空"); + zftMerchInfo.setLegalCertBackImage(upload(isvParams, applymentInfo.getIdcard2Img())); + } else { + // 小微需要上传身份证 + zftMerchInfo.setCertImage(upload(isvParams, applymentInfo.getIdcard1Img())); + zftMerchInfo.setCertImageBack(upload(isvParams, applymentInfo.getIdcard2Img())); + Assert.notNull(applymentInfo.getAlipayLogonId(), "个人商户只能结算到支付宝账户"); + } + + AddressInfo businessAddress = new AddressInfo(); + businessAddress.setProvinceCode(applymentInfo.getAreaCode().getString(0)); + businessAddress.setCityCode(applymentInfo.getAreaCode().getString(1)); + businessAddress.setDistrictCode(applymentInfo.getAreaCode().getString(2)); + businessAddress.setAddress(applymentInfo.getAddress()); + zftMerchInfo.setBusinessAddress(businessAddress); + + zftMerchInfo.setAliasName(applymentInfo.getMchShortName()); + + Assert.notNull(applymentInfo.getMccCode(), "mcc不能为空"); + String[] mccData = applymentInfo.getMccCode().split("_"); + if (mccData.length < 2) { + throw new BizException("mcc格式错误"); + } + zftMerchInfo.setMcc(mccData[1]); + + List contactInfosList = new ArrayList<>(); + ContactInfo contactInfo = new ContactInfo(); + contactInfo.setName(mchApplyment.getContactName()); + contactInfo.setPhone(mchApplyment.getContactPhone()); + contactInfo.setMobile(applymentInfo.getContactPhone()); + contactInfo.setIdCardNo(applymentInfo.getSettAccountIdcardNo()); + contactInfosList.add(contactInfo); + zftMerchInfo.setMerchantType(applymentInfo.convertMerchantType()); + + + if (!"alipayAccount".equals(applymentInfo.getDefaultSettleType()) + && MchApplyment.MERCHANT_TYPE_PERSONAL != applymentInfo.getMerchantType()) { + SettleCardInfo bizCard = getBizCards(applymentInfo); + + // 企业对私,需要授权函 + if (Objects.equals(applymentInfo.getMerchantType(), MchApplyment.MERCHANT_TYPE_ENTERPRISE) + && MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(applymentInfo.getSettAccountType())) { + zftMerchInfo.setLicenseAuthLetterImage(upload(isvParams, applymentInfo.getLicenseAuthLetterImage())); + } + + // 小微商户不能使用银行卡结算 + zftMerchInfo.setBizCards(Collections.singletonList(bizCard)); + zftMerchInfo.setLegalName(applymentInfo.getIdcardName()); + zftMerchInfo.setLegalCertNo(applymentInfo.getIdcardNo()); + zftMerchInfo.setLegalCertFrontImage(upload(isvParams, applymentInfo.getIdcard1Img())); + } else { + zftMerchInfo.setAlipayLogonId(applymentInfo.getAlipayLogonId()); + } + + zftMerchInfo.setCertImageBack(upload(isvParams, applymentInfo.getIdcard2Img())); + + List qualifications = getQualifications(applymentInfo, isvParams); + zftMerchInfo.setQualifications(qualifications); + zftMerchInfo.setService(applymentInfo.getServiceList()); + + + zftMerchInfo.setBindingAlipayLogonId(applymentInfo.getBindingAlipayLogonId()); + zftMerchInfo.setContactInfos(contactInfosList); + + List inDoorImages = new ArrayList<>(); + inDoorImages.add(upload(isvParams, applymentInfo.getStoreInnerImg())); + zftMerchInfo.setInDoorImages(inDoorImages); + + List outDoorImages = new ArrayList<>(); + outDoorImages.add(upload(isvParams, applymentInfo.getStoreOuterImg())); + zftMerchInfo.setOutDoorImages(outDoorImages); + + DefaultSettleRule defaultSettleRule = new DefaultSettleRule(); + defaultSettleRule.setDefaultSettleType(applymentInfo.getDefaultSettleType()); + if ("alipayAccount".equals(applymentInfo.getDefaultSettleType())) { + // 结算到支付宝 + defaultSettleRule.setDefaultSettleTarget(applymentInfo.getAlipayLogonId()); + } else { + // 结算到银行卡 + defaultSettleRule.setDefaultSettleTarget(applymentInfo.getSettAccountNo()); + } + + zftMerchInfo.setDefaultSettleRule(defaultSettleRule); + zftMerchInfo.setContactInfos(contactInfosList); + zftMerchInfo.setSites(applymentInfo.getSiteInfos().toJavaList(SiteInfo.class)); +// zftMerchInfo.put("sites", getSites(applymentInfo)); + + return zftMerchInfo; + } + + private static List getSites(ZftpayApplymentInfo applymentInfo) { + JSONArray siteInfos = applymentInfo.getSiteInfos(); + + List sites = new ArrayList<>(); + JSONObject item = new JSONObject(); + item.put("site_type", "01"); + item.put("site_url", "https://b.rscygroup.com/"); + item.put("site_name", "商福通"); + sites.add(item); + + item = new JSONObject(); + item.put("site_type", "02"); + item.put("site_name", "商福通"); + sites.add(item); + return sites; + } + + /** + * 特殊资质信息 + * @param applymentInfo 商户信息 + */ + private List getQualifications(ZftpayApplymentInfo applymentInfo, ZftpayIsvParams isvParams) { + if (ObjUtil.isEmpty(applymentInfo.getIndustryQualificationType())) { + return new ArrayList<>(); + } else { + if (ObjUtil.isEmpty(applymentInfo.getIndustryQualificationImage())) { + throw new BizException("商户行业资质图片不能为空"); + } + + IndustryQualificationInfo industryQualificationType = new IndustryQualificationInfo(); + industryQualificationType.setIndustryQualificationType(applymentInfo.getIndustryQualificationType()); + industryQualificationType.setIndustryQualificationImage(upload(isvParams, applymentInfo.getIndustryQualificationImage())); + + return Collections.singletonList(industryQualificationType); + } + } + + private SettleCardInfo getBizCards(ZftpayApplymentInfo applymentInfo) { + + SettleCardInfo bizCard = new SettleCardInfo(); + + String accountType = applymentInfo.getUseType(); + + bizCard.setAccountHolderName(applymentInfo.getSettAccountName()); + Assert.notNull(applymentInfo.getSettAccountBankBranchAreaName(), "开户行地区省市名称【settAccountBankBranchAreaName】不能为空"); + Assert.isTrue(applymentInfo.getSettAccountBankBranchAreaName().size() >= 2, "开户行地区省市名称有误"); + bizCard.setAccountInstProvince(applymentInfo.getSettAccountBankBranchAreaName().getString(0)); + bizCard.setAccountInstCity(applymentInfo.getSettAccountBankBranchAreaName().getString(1)); + bizCard.setAccountBranchName(applymentInfo.getSettAccountBankBranchName()); + bizCard.setUsageType(accountType); + + bizCard.setAccountType("DC"); + bizCard.setAccountInstName("DC"); + + Assert.notNull(applymentInfo.getSettAccountBankBranchCode(), "支行联行号不能为空"); + BankBranchZft branchZft = bankBranchZftService.lambdaQuery() + .eq(BankBranchZft::getBranchNo, applymentInfo.getSettAccountBankBranchCode()) + .one(); + + Assert.notNull(branchZft, "未找到支行信息"); + bizCard.setAccountInstName(branchZft.getBankName()); + bizCard.setAccountInstId(branchZft.getBankAbbr()); + bizCard.setBankCode(branchZft.getBranchNo()); + bizCard.setAccountNo(applymentInfo.getSettAccountNo()); + + return bizCard; + } + + private String upload(ZftpayIsvParams isvParams, String imgUrl) { + Assert.isTrue(!ObjectUtils.isEmpty(imgUrl), "【直付通】上传图片链接不能为空"); + JSONObject uploadResult = ZftpayKit.reqUpload(isvParams, ReqMethod.AUDIT_IMG_UPLOAD, imgUrl); + Assert.notNull(uploadResult, "直付通图片上传异常失败"); + return uploadResult.getString(Const.IMAGE_ID); + } + + @Override + public MchApplyment firstApplyment(MchApplyment mchApplyment) { + return IIsvmchApplymentService.super.firstApplyment(mchApplyment); + } + + @Override + public MchApplyment rejectModify(MchApplyment mchApplyment) { + return firstApplyment(mchApplyment); + } + + @Override + public MchApplyment replenishInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public MchApplyment query(MchApplyment mchApplyment) { + MchApplyment result = new MchApplyment(); + result.setApplyId(mchApplyment.getApplyId()); + result.setState(mchApplyment.getState()); + + ZftpayIsvParams isvParams = (ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment); + JSONObject reqParams = new JSONObject(); + if (ObjUtil.isEmpty(mchApplyment.getChannelApplyNo())) { + throw new BizException("未获取到直付通通道请求流水号"); + } + + AntMerchantExpandIndirectZftorderQueryModel zftorderQueryModel = new AntMerchantExpandIndirectZftorderQueryModel(); + zftorderQueryModel.setOrderId(mchApplyment.getChannelApplyNo()); + AntMerchantExpandIndirectZftorderQueryRequest queryRequest = new AntMerchantExpandIndirectZftorderQueryRequest(); + queryRequest.setBizModel(zftorderQueryModel); + AntMerchantExpandIndirectZftorderQueryResponse resp = ZftpayKit.req(isvParams, queryRequest); + List orders = resp.getOrders(); + + for (int i = 0; i < orders.size(); i++) { + ZftSubMerchantOrder order = orders.get(i); + if (!mchApplyment.getChannelApplyNo().equals(order.getOrderId())) { + break; + } else { + result.setChannelVar1(JSON.toJSONString(order)); + } + + JSONObject channelVar2 = ((JSONObject) JSON.toJSON(order)); + String status = order.getStatus(); + String fkAudit = order.getFkAudit(); + String kzAudit = order.getKzAudit(); + String subConfirm = order.getSubConfirm(); + + // 审核最终状态 + if ("99".equals(status)) { + // 审核通过 + String smid = order.getSmid(); + result.setState(MchApplyment.STATE_SUCCESS); + result.setChannelMchNo(smid); + + return result; + } + + if ("-1".equals(status)) { + // 审核驳回 + String reason = order.getReason(); + result.setState(MchApplyment.STATE_REJECT_WAIT_MODIFY); + result.setApplyErrorInfo("[" + reason + "]"); + return result; + } + + // 签约状态, 已发起商户确认 + if ("CREATE".equals(subConfirm)) { + // 待签约确认 + // 签约链接 + String subSignQrCodeUrl = order.getSubSignQrCodeUrl(); + channelVar2.put("signUrl", subSignQrCodeUrl); + result.setChannelVar2(channelVar2.toJSONString()); + result.setState(MchApplyment.STATE_WAIT_SIGN); + + return result; + } + + // 其他状态暂不处理 + } + + + return result; + } + + @Override + public ApplymentSignInfo signInfo(MchApplyment mchApplyment) { + return null; + } + + @Override + public void cancel(MchApplyment mchApplyment) { + if (ObjUtil.isEmpty(mchApplyment.getApplyId())) { + throw new BizException("进件号不能为空"); + } + + ZftpayIsvParams isvParams = ((ZftpayIsvParams) configContextQueryService.queryIsvParams(mchApplyment)); + // 直付通二级商户作废 + String channelMchNo = mchApplyment.getChannelMchNo(); + JSONObject param = new JSONObject(); + AntMerchantExpandIndirectZftDeleteModel model = new AntMerchantExpandIndirectZftDeleteModel(); + model.setSmid(channelMchNo); + AntMerchantExpandIndirectZftDeleteRequest request = new AntMerchantExpandIndirectZftDeleteRequest(); + request.setBizModel(model); + + AntMerchantExpandIndirectZftDeleteResponse response = ZftpayKit.req(isvParams, request); + + // 更新商户状态 + mchApplymentService.lambdaUpdate() + .eq(com.jeequan.jeepay.db.entity.MchApplyment::getApplyId, mchApplyment.getApplyId()) + .set(com.jeequan.jeepay.db.entity.MchApplyment::getState, MchApplyment.STATE_WAIT_LOGOUT) + .update(); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderQueryService.java new file mode 100644 index 0000000..c8d1a21 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderQueryService.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import com.alipay.api.domain.AlipayTradeQueryModel; +import com.alipay.api.request.AlipayTradeQueryRequest; +import com.alipay.api.response.AlipayTradeQueryResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderQueryService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 支付宝直付通 查单接口实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:20 +*/ +@Service +public class ZftpayPayOrderQueryService implements IPayOrderQueryService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AlipayTradeQueryRequest req = new AlipayTradeQueryRequest(); + // 商户订单号,商户网站订单系统中唯一订单号,必填 + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + model.setOutTradeNo(payOrder.getPayOrderId()); + req.setBizModel(model); + AlipayTradeQueryResponse resp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req); + String result = resp.getTradeStatus(); + if("TRADE_SUCCESS".equals(result)) { + return ChannelRetMsg.confirmSuccess(resp.getTradeNo(), resp.getTradeNo(), payOrder.getPayOrderId(),null); //支付成功 + }else if("WAIT_BUYER_PAY".equals(result)) { + return ChannelRetMsg.waiting(); //支付中 + } + return ChannelRetMsg.waiting(); //支付中 + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderSettService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderSettService.java new file mode 100644 index 0000000..90e4b40 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPayOrderSettService.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeSettleConfirmModel; +import com.alipay.api.domain.SettleDetailInfo; +import com.alipay.api.domain.SettleInfo; +import com.alipay.api.request.AlipayTradeSettleConfirmRequest; +import com.alipay.api.response.AlipayTradeSettleConfirmResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderSettService; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.model.ZftpayClientWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 直付通订单确认结算 + * + * **/ +@Service +public class ZftpayPayOrderSettService implements IPayOrderSettService { + + @Autowired + private ConfigContextQueryService configContextQueryService; + + /** + * 直付通确认结算 + * @param payOrder + * @param channelTradeNo + * @return + */ + @Override + public ChannelRetMsg tradeSettleConfirm(PayOrder payOrder, String channelTradeNo,String settleNo) { + ZftpayClientWrapper zftpayClientWrapper = configContextQueryService.getZftpayClientWrapper(payOrder.getIsvNo()); + AlipayTradeSettleConfirmRequest request = new AlipayTradeSettleConfirmRequest(); + AlipayTradeSettleConfirmModel model = new AlipayTradeSettleConfirmModel(); + model.setOutRequestNo(settleNo); + model.setTradeNo(channelTradeNo); + SettleInfo settleInfo = new SettleInfo(); + List list = new ArrayList<>(); + SettleDetailInfo detailInfo = new SettleDetailInfo(); + detailInfo.setTransInType("defaultSettle"); + detailInfo.setAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + detailInfo.setSettleEntityId(payOrder.getChannelMchNo()); + detailInfo.setSettleEntityType("SecondMerchant"); + list.add(detailInfo); + settleInfo.setSettleDetailInfos(list); + model.setSettleInfo(settleInfo); + request.setBizModel(model); + try { + AlipayTradeSettleConfirmResponse response = zftpayClientWrapper.getAlipayClient().execute(request); + if(response.isSuccess()){ + return ChannelRetMsg.confirmSuccess(response.getTradeNo()); + } + return ChannelRetMsg.confirmFail(response.getTradeNo(),response.getCode(),response.getMsg()); + } catch (AlipayApiException e) { + return ChannelRetMsg.confirmFail(e.getErrCode(),e.getErrMsg()); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPaymentService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPaymentService.java new file mode 100644 index 0000000..67bf795 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayPaymentService.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.domain.SettleDetailInfo; +import com.alipay.api.domain.SettleInfo; +import com.alipay.api.domain.SubMerchant; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.db.entity.AccountInfo; +import com.jeequan.jeepay.service.impl.AccountInfoService; +import com.jeequan.jeepay.thirdparty.channel.AbstractPaymentService; +import com.jeequan.jeepay.thirdparty.util.PaywayUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * TODO + * 支付宝直付通 + * @author crystal + * @date 2024/3/27 18:07 + */ +@Service +public class ZftpayPaymentService extends AbstractPaymentService { + + @Autowired + private AccountInfoService accountInfoService; + + /** + * 支付宝直付通 + * @return + */ + @Override + public String getIfCode() { + return CS.IF_CODE.ZFTPAY; + } + + @Override + public boolean isSupport(String wayCode) { + return false; + } + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + this.checkAccountBlance(payOrder); + if(!CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(payOrder.getWayCodeType())){ + throw new BizException("直付通只支持支付宝支付"); + } + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).preCheck(rq, payOrder); + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + return PaywayUtil.getRealPaywayService(this, payOrder.getWayCode()).pay(rq, payOrder, mchAppConfigContext); + } + + public static T getPayModel(UnifiedOrderRQ rq, PayOrder payOrder, Class clazz) { + JSONObject result = new JSONObject(); + result.put("outTradeNo",payOrder.getPayOrderId()); + result.put("subject",payOrder.getSubject()); + result.put("body",payOrder.getBody()); + result.put("totalAmount", AmountUtil.convertCent2Dollar(payOrder.getFindAmt().toString())); + result.put("timeExpire", DateUtil.format(payOrder.getExpiredTime(), DatePattern.NORM_DATETIME_FORMAT)); + SubMerchant subMerchant = new SubMerchant(); + subMerchant.setMerchantId(payOrder.getChannelMchNo()); + SettleInfo settleInfo = new SettleInfo(); + settleInfo.setSettlePeriodTime("30d"); + SettleDetailInfo settleDetailInfo = new SettleDetailInfo(); + //固定传值 + settleDetailInfo.setTransInType("defaultSettle"); + settleDetailInfo.setAmount(AmountUtil.convertCent2Dollar(payOrder.getFindAmt())); + List list = new ArrayList<>(); + list.add(settleDetailInfo); + settleInfo.setSettleDetailInfos(list); + result.put("subMerchant",subMerchant); + result.put("settleInfo",settleInfo); + Integer limitPay = rq.getLimitPay(); + if(limitPay != null && limitPay == 1){ + result.put("disablePayChannels","creditCard"); + } + return result.toJavaObject(clazz); + } + + /** + * 值付通走的是手续费账户模式,校验手续费账户余额 + */ + public void checkAccountBlance(PayOrder payOrder){ + accountInfoService.checkBalance(payOrder.getMchNo(),AccountInfo.Type.SERVICE_CHARGE,payOrder.getMchOrderFeeAmount()); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayRefundService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayRefundService.java new file mode 100644 index 0000000..92af411 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/ZftpayRefundService.java @@ -0,0 +1,101 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay; + +import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel; +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; +import com.alipay.api.response.AlipayTradeRefundResponse; +import com.jeequan.jeepay.core.constants.CS; +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; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.AbstractRefundService; +import org.springframework.stereotype.Service; + +/* +* 退款接口:支付宝直付通退款 +* +* @author terrfly +* +* @date 2021/6/17 9:38 +*/ +@Service +public class ZftpayRefundService extends AbstractRefundService { + + @Override + public String getIfCode() { + return CS.IF_CODE.ZFTPAY; + } + + @Override + public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) { + return null; + } + + @Override + public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + AlipayTradeRefundModel model = new AlipayTradeRefundModel(); + model.setOutTradeNo(refundOrder.getPayOrderId()); + model.setTradeNo(refundOrder.getChannelPayOrderNo()); + model.setOutRequestNo(refundOrder.getRefundOrderId()); + model.setRefundAmount(AmountUtil.convertCent2Dollar(refundOrder.getRefundAmount().toString())); + model.setRefundReason(refundOrder.getRefundReason()); + request.setBizModel(model); + AlipayTradeRefundResponse response = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).execute(request); + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + retMsg.setChannelAttach(response.getBody()); + // 调用成功 + if(response.isSuccess()){ + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + retMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + retMsg.setChannelErrCode(response.getSubCode()); + retMsg.setChannelErrMsg(response.getSubMsg()); + } + return retMsg; + } + + @Override + public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception { + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); + model.setTradeNo(refundOrder.getChannelPayOrderNo()); + model.setOutTradeNo(refundOrder.getPayOrderId()); + model.setOutRequestNo(refundOrder.getRefundOrderId()); + request.setBizModel(model); + AlipayTradeFastpayRefundQueryResponse response = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).execute(request); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + channelRetMsg.setChannelAttach(response.getBody()); + // 调用成功 & 金额相等 (传入不存在的outRequestNo支付宝仍然返回响应成功只是数据不存在, 调用isSuccess() 仍是成功, 此处需判断金额是否相等) + Long channelRefundAmount = response.getRefundAmount() == null ? null : Long.parseLong(AmountUtil.convertDollar2Cent(response.getRefundAmount())); + if(response.isSuccess() && refundOrder.getRefundAmount().equals(channelRefundAmount)){ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); //认为是处理中 + } + return channelRetMsg; + } + + @Override + public void checkPlatAccount(RefundOrder refundOrder) { + + } + + /** + * 退款权限 + * @param settleType + * @param applyId + * @return + */ + @Override + public ChannelRefundLimit isRefundLimit(String settleType,String applyId) { + return super.isRefundLimit(settleType,applyId); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/Const.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/Const.java new file mode 100644 index 0000000..0d2b6d2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/Const.java @@ -0,0 +1,8 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.model; + +public class Const { + + public static final String GATE_WAY = "https://openapi.alipay.com/gateway.do"; + + public static final String IMAGE_ID = "image_id"; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqEntity.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqEntity.java new file mode 100644 index 0000000..aff2a63 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqEntity.java @@ -0,0 +1,113 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.model; + +import cn.hutool.core.date.DateUtil; +import com.alipay.api.FileItem; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.Date; + +/** + * 线上对接请求参数 + */ +@Setter +@Getter +public class ReqEntity implements Serializable { + + public static final String DEFAULT_CHARSET = "UTF-8"; + + public static final String DEFAULT_FORMAT = "json"; + + public static final String DEFAULT_SIGN_TYPE = "RSA2"; + + public static final String DEFAULT_VERSION = "1.0"; + + /** + * 支付宝分配给开发者的应用ID + */ + private String app_id; + + /** + * 接口名称 + */ + private String method; + + /** + * 仅支持JSON + */ + private String format; + + /** + * 请求使用的编码格式,如utf-8,gbk,gb2312等 + */ + private String charset; + + /** + * 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 + */ + private String sign_type; + + /** + * RSA签名字符串,再用Base64编码 + */ + private String sign; + + /** + * 发送请求的时间,格式"yyyy-MM-dd HH:mm:ss" + */ + private String timestamp; + + /** + * 调用的接口版本,固定为:1.0 + */ + private String version; + + /** + * 支付宝服务器主动通知商户服务器里指定的页面http/https路径。 + */ + private String notify_url; + + /** + * 详见应用授权概述 https://opendocs.alipay.com/isv/10467/xldcyq + */ + private String app_auth_token; + + /** + * 请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档 + */ + private String biz_content; + + /** + * 支付成功跳转地址 + */ + private String return_url; + /** + * 图片类型 + */ + private String image_type; + /** + * 图片内容 + */ + private FileItem image_content; + + public ReqEntity(ReqMethod method, String appid, String notifyUrl, String returnUrl) { + this.app_id = appid; + this.method = method.getMethod(); + this.format = DEFAULT_FORMAT; + this.charset = DEFAULT_CHARSET; + this.sign_type = DEFAULT_SIGN_TYPE; + this.timestamp = DateUtil.formatDateTime(new Date()); + this.version = DEFAULT_VERSION; + this.notify_url = notifyUrl; + this.return_url = returnUrl; + } + + public ReqEntity(ReqMethod method, String appid) { + this(method,appid,null,null); + } + + public ReqEntity(ReqMethod method, String appid, String notifyUrl) { + this(method,appid,notifyUrl,null); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqMethod.java new file mode 100644 index 0000000..5ed44ef --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/model/ReqMethod.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum ReqMethod { + + APP(Const.GATE_WAY, "alipay.trade.app.pay", "alipay_trade_app_pay_response"), + + WAP(Const.GATE_WAY, "alipay.trade.wap.pay", "alipay_trade_wap_pay_response"), + + /** + * 入网前预校验 + */ + AUDIT_PRE_CHECK(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.consult", "ant_merchant_expand_indirect_zft_consult_response"), + + /** + * 入网上传图片信息 + */ + AUDIT_IMG_UPLOAD(Const.GATE_WAY, "ant.merchant.expand.indirect.image.upload", "ant_merchant_expand_indirect_image_upload_response"), + + /** + * 直付通二级商户创建 + */ + AUDIT_MERCH_CREATE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.create", "ant_merchant_expand_indirect_zft_create_response"), + + /** + * 直付通二级商户免证件照创建 + */ + AUDIT_MERCH_SIMPLE_CREATE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.simplecreate", "ant_merchant_expand_indirect_zft_simplecreate_response"), + + /** + * 商户入驻查询 + */ + AUDIT_RESULT_QUERY(Const.GATE_WAY, "ant.merchant.expand.indirect.zftorder.query", "ant_merchant_expand_indirect_zftorder_query_response"), + + /** + * 通过通知 + */ + AUDIT_PASS_NOTICE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.passed", "ant_merchant_expand_indirect_zft_passed_response"), + + /** + * 个人限额升级 + */ + MERCH_UPGRADE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.upgrade", "ant_merchant_expand_indirect_zft_upgrade_response"), + + /** + * 商户作废 + */ + MERCH_DELETE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.delete", "ant_merchant_expand_indirect_zft_delete_response"), + + /** + * 商户信息修改 + */ + MERCH_MODIFY(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.modify", "ant_merchant_expand_indirect_zft_modify_response"), + + /** + * 驳回通知 + */ + AUDIT_REJECT_NOTICE(Const.GATE_WAY, "ant.merchant.expand.indirect.zft.rejected", "ant_merchant_expand_indirect_zft_rejected_response"), + + COMFRIM(Const.GATE_WAY, "alipay.trade.settle.confirm", "alipay_trade_settle_confirm_response"), + + SETTLE(Const.GATE_WAY, "alipay.trade.order.settle", "alipay_trade_order_settle_response"), + + SETTLE_QUERY(Const.GATE_WAY, "alipay.trade.order.settle.query", "alipay_trade_order_settle_query_response"), + + ONSETTLE_QUERY(Const.GATE_WAY, "alipay.trade.order.onsettle.query", "alipay_trade_order_onsettle_query_response"), + + REFUND(Const.GATE_WAY, "alipay.trade.refund", "alipay_trade_refund_response"), + + REFUND_QUERY(Const.GATE_WAY, "alipay.trade.fastpay.refund.query", "alipay_trade_fastpay_refund_query_response"), + + BIND(Const.GATE_WAY, "alipay.trade.royalty.relation.bind", "alipay_trade_royalty_relation_bind_response"), + + UNBIND(Const.GATE_WAY, "alipay.trade.royalty.relation.unbind", "alipay_trade_royalty_relation_unbind_response"), + + TRADE_QUERY("https://openapi.alipay.com/gateway.do", "alipay.trade.query", "alipay_trade_query_response"), + + CERT_VERIFY_PRE_CONSULT("https://openapi.alipay.com/gateway.do", "alipay.user.certdoc.certverify.preconsult", "alipay_user_certdoc_certverify_preconsult_response"), + + CERT_VERIFY_CONSULT("https://openapi.alipay.com/gateway.do", "alipay.user.certdoc.certverify.consult", "alipay_user_certdoc_certverify_consult_response"); + + private final String url; + + private final String method; + + private final String responseKey; + +// public static ReqMethod getVal(String type) { +// ThirdPay.PayWay val = ThirdPay.PayWay.getVal(type); +// if (val == null) { +// return WAP; +// } +// +// switch (val) { +// case APP -> { +// return ReqMethod.APP; +// } +// } +// return WAP; +// } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliApp.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliApp.java new file mode 100644 index 0000000..620811e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliApp.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayObject; +import com.alipay.api.domain.AlipayTradeAppPayModel; +import com.alipay.api.domain.SettleDetailInfo; +import com.alipay.api.domain.SettleInfo; +import com.alipay.api.domain.SubMerchant; +import com.alipay.api.request.AlipayTradeAppPayRequest; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliAppOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/* +* 支付宝直付通 +*/ +@Service("zftpayPaymentByAliAppService") +public class AliApp extends ZftpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + /** + * product_code 为产品码,按实际使用修改。APP支付上送:QUICK_MSECURITY_PAY, + * 手机网站支付上送:QUICK_WAP_WAY, + * 电脑网站支付上送:FAST_INSTANT_TRADE_PAY, + * JSAPI支付上送:JSAPI_PAY。 + */ + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AlipayTradeAppPayRequest req = new AlipayTradeAppPayRequest(); + AlipayTradeAppPayModel model = getPayModel(rq,payOrder,AlipayTradeAppPayModel.class); + req.setNotifyUrl(getNotifyUrl()); + model.setProductCode("QUICK_MSECURITY_PAY"); + req.setBizModel(model); + String payData = null; + try { + payData = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().sdkExecute(req).getBody(); + } catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + // 构造函数响应数据 + AliAppOrderRS res = ApiResBuilder.buildSuccess(AliAppOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + //放置 响应数据 + channelRetMsg.setChannelAttach(payData); + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + res.setPayData(payData); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliJsapi.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliJsapi.java new file mode 100644 index 0000000..bf5f621 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliJsapi.java @@ -0,0 +1,75 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradeCreateModel; +import com.alipay.api.request.AlipayTradeCreateRequest; +import com.alipay.api.response.AlipayTradeCreateResponse; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliJsapiOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 支付宝 直付通 jsapi支付 + * + * @author terrfly + * + * @date 2021/6/8 17:20 + */ +@Service("zftpayPaymentByJsapiService") //Service Name需保持全局唯一性 +public class AliJsapi extends ZftpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + AliJsapiOrderRQ bizRQ = (AliJsapiOrderRQ) rq; + AlipayTradeCreateRequest req = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = getPayModel(rq, payOrder, AlipayTradeCreateModel.class); + model.setBuyerId(bizRQ.getBuyerUserId()); + model.setProductCode("JSAPI_PAY"); + req.setNotifyUrl(getNotifyUrl()); + req.setBizModel(model); + AlipayTradeCreateResponse alipayResp = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).execute(req); + // 构造函数响应数据 + AliJsapiOrderRS res = ApiResBuilder.buildSuccess(AliJsapiOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + res.setAlipayTradeNo(alipayResp.getTradeNo()); + channelRetMsg.setChannelOrderId(alipayResp.getTradeNo()); + if(alipayResp.isSuccess()){ //业务处理成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliLite.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliLite.java new file mode 100644 index 0000000..b469bc1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliLite.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.domain.AlipayTradeCreateModel; +import com.alipay.api.request.AlipayTradeCreateRequest; +import com.alipay.api.response.AlipayTradeCreateResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliLiteOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayPaymentService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 支付宝直付通 小程序支付 + * @date 2021/6/8 17:20 + */ +@Service("zftpayPaymentByLiteService") //Service Name需保持全局唯一性 +public class AliLite extends ZftpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + if(StringUtils.isEmpty(bizRQ.getBuyerUserId())){ + throw new BizException("[buyerUserId]不可为空"); + } + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception{ + AliLiteOrderRQ bizRQ = (AliLiteOrderRQ) rq; + AlipayTradeCreateRequest req = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = getPayModel(rq, payOrder, AlipayTradeCreateModel.class); + model.setBuyerId(bizRQ.getBuyerUserId()); + ConfigContextQueryService configContextQueryService = SpringBeansUtil.getBean(ConfigContextQueryService.class); + AlipayOauth2Params oauth2Params = (AlipayOauth2Params) configContextQueryService.queryIsvOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + model.setProductCode("JSAPI_PAY"); + model.setOpAppId(oauth2Params.getLiteParams().getAppId()); + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setBizModel(model); + //统一放置 isv接口必传信息 +// AlipayKit.putApiIsvInfo(mchAppConfigContext, req, model); + + //调起支付宝 (如果异常, 将直接跑出 ChannelException ) + AlipayTradeCreateResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).getAlipayClientByOauth2Lite().getAlipayClient().execute(req); +// AlipayTradeCreateResponse alipayResp = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).execute(req); + + // 构造函数响应数据 + AliLiteOrderRS res = ApiResBuilder.buildSuccess(AliLiteOrderRS.class); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelAttach(alipayResp.getBody()); + + // ↓↓↓↓↓↓ 调起接口成功后业务判断务必谨慎!! 避免因代码编写bug,导致不能正确返回订单状态信息 ↓↓↓↓↓↓ + res.setAlipayTradeNo(alipayResp.getTradeNo()); + + channelRetMsg.setChannelOrderId(alipayResp.getTradeNo()); + if(alipayResp.isSuccess()){ //业务处理成功 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + + }else{ + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(alipayResp.getCode(), alipayResp.getSubCode())); + channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(alipayResp.getMsg(), alipayResp.getSubMsg())); + } + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliPc.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliPc.java new file mode 100644 index 0000000..43d48c9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliPc.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradePagePayModel; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliPcOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliPcOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayPaymentService; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝 PC支付 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service("zftpayPaymentByAliPcService") //Service Name需保持全局唯一性 +public class AliPc extends ZftpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliPcOrderRQ bizRQ = (AliPcOrderRQ) rq; + AlipayTradePagePayRequest req = new AlipayTradePagePayRequest(); + AlipayTradePagePayModel model = getPayModel(rq, payOrder, AlipayTradePagePayModel.class); + model.setProductCode("FAST_INSTANT_TRADE_PAY"); + model.setQrPayMode("2"); //订单码-跳转模式 + req.setNotifyUrl(getNotifyUrl()); // 设置异步通知地址 + req.setReturnUrl(getReturnUrl()); // 同步跳转地址 + req.setBizModel(model); + // 构造函数响应数据 + AliPcOrderRS res = ApiResBuilder.buildSuccess(AliPcOrderRS.class); + try { + if(CS.PAY_DATA_TYPE.FORM.equals(bizRQ.getPayDataType())){ + res.setFormContent(configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().pageExecute(req).getBody()); + }else{ + res.setPayUrl(configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().pageExecute(req, "GET").getBody()); + } + }catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + + //放置 响应数据 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliWap.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliWap.java new file mode 100644 index 0000000..680576d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/channel/zftpay/payway/AliWap.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.thirdparty.channel.zftpay.payway; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.domain.AlipayTradeWapPayModel; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliWapOrderRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.AliWapOrderRS; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.channel.alipay.AlipayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayKit; +import com.jeequan.jeepay.thirdparty.channel.zftpay.ZftpayPaymentService; +import com.jeequan.jeepay.thirdparty.util.ApiResBuilder; +import org.springframework.stereotype.Service; + +/* +* 支付宝直付通 wap支付 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service("zftpayPaymentByAliWapService") //Service Name需保持全局唯一性 +public class AliWap extends ZftpayPaymentService { + + @Override + public String preCheck(UnifiedOrderRQ rq, PayOrder payOrder) { + return null; + } + + @Override + public AbstractRS pay(UnifiedOrderRQ rq, PayOrder payOrder, MchAppConfigContext mchAppConfigContext){ + AliWapOrderRQ bizRQ = (AliWapOrderRQ)rq; + AlipayTradeWapPayRequest req = new AlipayTradeWapPayRequest(); + AlipayTradeWapPayModel model = getPayModel(rq, payOrder, AlipayTradeWapPayModel.class); + req.setNotifyUrl(getNotifyUrl()); + model.setProductCode("QUICK_WAP_WAY"); + // 构造函数响应数据 + req.setBizModel(model); + AliWapOrderRS res = ApiResBuilder.buildSuccess(AliWapOrderRS.class); + try { + if(CS.PAY_DATA_TYPE.FORM.equals(bizRQ.getPayDataType())){ //表单方式 + res.setFormContent(configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().pageExecute(req).getBody()); + }else if (CS.PAY_DATA_TYPE.CODE_IMG_URL.equals(bizRQ.getPayDataType())){ //二维码图片地址 + String payUrl = configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().pageExecute(req, "GET").getBody(); + res.setCodeImgUrl(sysConfigService.getDBApplicationConfig().genScanImgUrl(payUrl)); + }else{ // 默认都为 payUrl方式 + res.setPayUrl(configContextQueryService.getZftpayClientWrapper(mchAppConfigContext).getAlipayClient().pageExecute(req, "GET").getBody()); + } + }catch (AlipayApiException e) { + throw ChannelException.sysError(e.getMessage()); + } + res.setPayDataType(res.buildPayDataType()); + res.setPayData(res.buildPayData()); + ChannelRetMsg channelRetMsg = new ChannelRetMsg(); + res.setChannelRetMsg(channelRetMsg); + //放置 响应数据 + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + return res; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/bsjPrinter/BsjPrinterService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/bsjPrinter/BsjPrinterService.java new file mode 100644 index 0000000..1d67547 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/bsjPrinter/BsjPrinterService.java @@ -0,0 +1,143 @@ +package com.jeequan.jeepay.thirdparty.device.printer.bsjPrinter; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.device.BsjParams; +import com.jeequan.jeepay.core.model.device.DeviceParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.thirdparty.device.speaker.bsjSpeaker.BsjUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 云打印厂商: 智谷物联 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class BsjPrinterService implements IPrinterService { + + private static final String REQ_URL = "https://ioe.car900.com/v1/openApi/dev/customPrint.json"; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + JSONObject resJSON = print(deviceParams, payOrderInfo); + if (resJSON == null) { + throw new BizException("请求失败"); + } + if (resJSON.getIntValue("code") != 0) { + throw new BizException(resJSON.getString("msg")); + } + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + BsjParams bsjParams = getBsjParams(deviceParams); + + // 设置播报、打印并播报才执行自定义播报 + if (bsjParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_SPEAK || bsjParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_PRINT_AND_SPEAK) { + JSONObject reqParams = new JSONObject(); + reqParams.put("actWay", DeviceParams.MODE_SPEAK); + reqParams.put("voiceJson", BsjUtil.getSpeakData(bsjParams.getProviderParams().getCustomContent(), payOrderInfo).toJSONString()); + + JSONObject resJSON = BsjUtil.post(REQ_URL, bsjParams, reqParams); + if (resJSON == null) { + throw new BizException("请求失败"); + } + if (resJSON.getIntValue("code") != 0) { + throw new BizException(resJSON.getString("msg")); + } + }else { + throw new BizException("打印机未设置播报模式"); + } + } + + @Override + public String addPrinter(JSONObject deviceParams) { + return null; + } + + @Override + public String editPrinter(JSONObject deviceParams) { + return null; + } + + @Override + public String clearPrinter(JSONObject deviceParams) { + return null; + } + + + /** + * 发起请求 + */ + private JSONObject print(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + BsjParams bsjParams = getBsjParams(deviceParams); + + // 打印联数 + int printNum = bsjParams.getBizConfigParams().getPrintNum() != null ? bsjParams.getBizConfigParams().getPrintNum() : 1; + + JSONObject reqParams = new JSONObject(); + reqParams.put("actWay", bsjParams.getBizConfigParams().getPrintMode()); + + // 仅播报 + if (bsjParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_SPEAK) { + reqParams.put("voiceJson", BsjUtil.getSpeakData(bsjParams.getProviderParams().getCustomContent(), payOrderInfo).toJSONString()); + return BsjUtil.post(REQ_URL, bsjParams, reqParams); + + } + // 仅打印 + else if (bsjParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_PRINT) { + + reqParams.put("data", getPrintData(payOrderInfo)); + reqParams.put("cn", printNum); // 打印联数 + return BsjUtil.post(REQ_URL, bsjParams, reqParams); + + } + // 打印并播报 + else { + + reqParams.put("data", getPrintData(payOrderInfo)); + reqParams.put("voiceJson", BsjUtil.getSpeakData(bsjParams.getProviderParams().getCustomContent(), payOrderInfo).toJSONString()); + reqParams.put("cn", printNum); // 打印联数 + return BsjUtil.post(REQ_URL, bsjParams, reqParams); + } + } + + + + /** 获取打印内容 */ + public String getPrintData(PayOrderInfo4Device payOrderInfo) { + + String storeName = StringUtils.isNotBlank(payOrderInfo.getStoreName()) ? payOrderInfo.getStoreName() : "门店名称"; + + return ""+storeName+"
" + + "----------------
" + + "订单编号: "+payOrderInfo.getPayOrderId()+"
" + + "下单时间: "+DateUtil.format(payOrderInfo.getCreatedAt(), DatePattern.NORM_DATETIME_FORMAT)+"
" + + (StringUtils.isNotBlank(payOrderInfo.getRemark()) ? "备 注: "+payOrderInfo.getRemark()+"
" : "") + + "实付: ¥"+BsjUtil.covertMoney(payOrderInfo.getAmount())+"
" + + ""; + } + + private BsjParams getBsjParams(JSONObject deviceParams) { + JSONObject bsjJSON = new JSONObject(); + bsjJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + bsjJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + bsjJSON.put("bizConfigParams", JSON.parseObject(deviceParams.getString("bizConfigParams"))); + + return JSON.parseObject(bsjJSON.toJSONString(), BsjParams.class); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FePrinterService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FePrinterService.java new file mode 100644 index 0000000..372cfc6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FePrinterService.java @@ -0,0 +1,139 @@ +package com.jeequan.jeepay.thirdparty.device.printer.fePrinter; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.device.FePrinterParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 云打印厂商: 飞鹅 + * + * @author zhuxiao + * @date 2021/6/8 18:10 + */ +@Slf4j +@Service +public class FePrinterService implements IPrinterService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) { + + try { + + // 飞鹅云打印参数 + FePrinterParams fePrinterParams = getFePrintParams(deviceParams); + + // 消息体 + String result = FeUtil.print(fePrinterParams, createMessage(printPayOrderInfo)); + if (result == null) { + throw new BizException("打印失败"); + } + + } catch (Exception e) { + log.error("飞鹅云打印机打印失败", e); + throw new BizException(e.getMessage()); + } + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) throws BizException { + return; + } + + @Override + public String addPrinter(JSONObject deviceParams) { + + try { + return FeUtil.addPrinter(getFePrintParams(deviceParams)); + } catch (Exception e) { + log.error("新增飞鹅云打印机失败", e); + throw new BizException(e.getMessage()); + } + } + + @Override + public String editPrinter(JSONObject deviceParams) { + + try { + return FeUtil.editPrinter(getFePrintParams(deviceParams)); + } catch (Exception e) { + log.error("编辑飞鹅云打印机失败", e); + throw new BizException(e.getMessage()); + } + } + + @Override + public String clearPrinter(JSONObject deviceParams) { + + try { + return FeUtil.clear(getFePrintParams(deviceParams)); + } catch (Exception e) { + log.error("清空飞鹅打印队列失败", e); + throw new BizException(e.getMessage()); + } + } + + private FePrinterParams getFePrintParams(JSONObject deviceParams) { + JSONObject paramsJSON = new JSONObject(); + paramsJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + paramsJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + if (StringUtils.isNotBlank(deviceParams.getString("bizConfigParams"))) { + paramsJSON.put("bizConfigParams", JSON.parseObject(deviceParams.getString("bizConfigParams"))); + } + + // 飞鹅云打印参数 + return JSON.parseObject(paramsJSON.toJSONString(), FePrinterParams.class); + } + + /** + * 根据订单 生成云打印机打印内容 + * messageJSON应包含: + * tradeOrderId 订单ID,goodsJson为空时,必传 + * storeName 门店名称,非必传 + * goodsJson 商品信息JSON,非必传 + * amount 支付金额,goodsJson为空时,必传 + * storeAreaName 门店区域/桌号名称,非必传 + * createTime 下单时间 + */ + public String createMessage(PayOrderInfo4Device printPayOrderInfo) { + + String payOrderId = printPayOrderInfo.getPayOrderId(); + + //标签说明: + //"
"为换行,""为切刀指令(主动切纸,仅限切刀打印机使用才有效果) + //""为打印LOGO指令(前提是预先在机器内置LOGO图片),""为钱箱或者外置音响指令 + //成对标签: + //""为居中放大一倍,""为放大一倍,""为居中,字体变高一倍 + //字体变宽一倍,""为二维码,""为字体加粗,""为右对齐 + + // 门店名称 + String storeName = printPayOrderInfo.getStoreName(); + storeName = StringUtils.isNotBlank(storeName) ? storeName : "计全科技"; + + // 打印内容 + String content = "" + storeName + "
"; + + //金额 + String amount = AmountUtil.convertCent2Dollar(printPayOrderInfo.getAmount()); + + content += "--------------------------------
"; + if (StringUtils.isNotBlank(payOrderId)) { + content += "订单号:" + payOrderId + "
"; + } + content += "订单金额:" + amount + "元
"; + content += "下单时间:" + DateUtil.format(printPayOrderInfo.getCreatedAt(), DatePattern.NORM_DATETIME_FORMAT) + "
"; + // content += "
https://www.jeequan.com/"; + + return content; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FeUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FeUtil.java new file mode 100644 index 0000000..9fd4a89 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/fePrinter/FeUtil.java @@ -0,0 +1,162 @@ +package com.jeequan.jeepay.thirdparty.device.printer.fePrinter; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.FePrinterParams; +import com.jeequan.jeepay.core.utils.DateKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/6 +*/ +@Slf4j +public class FeUtil { + + public static final String REQ_URL = "http://api.feieyun.cn/Api/Open/"; + + /** + * @Author: ZhuXiao + * @Description: 添加打印机至飞鹅后台 + * @Date: 9:51 2021/7/7 + */ + public static String addPrinter(FePrinterParams fePrinterParams) throws Exception { + + List nvps = FeUtil.genIsvParams(fePrinterParams); + String snStr = String.format("%s#%s#%s", fePrinterParams.getDeviceParams().getDeviceNo(), fePrinterParams.getDeviceParams().getDeviceKey(), fePrinterParams.getDeviceParams().getDeviceNo()); + nvps.add(new BasicNameValuePair("apiname", "Open_printerAddlist")); + nvps.add(new BasicNameValuePair("printerContent", snStr)); + + return FeUtil.post(FeUtil.REQ_URL, nvps); + } + + /** + * @Author: ZhuXiao + * @Description: 修改飞鹅后台打印机信息 + * @Date: 10:51 2021/7/7 + */ + public static String editPrinter(FePrinterParams fePrinterParams) throws Exception { + + List nvps = FeUtil.genIsvParams(fePrinterParams); + nvps.add(new BasicNameValuePair("apiname", "Open_printerEdit")); + nvps.add(new BasicNameValuePair("sn", fePrinterParams.getDeviceParams().getDeviceNo())); + nvps.add(new BasicNameValuePair("name", fePrinterParams.getDeviceParams().getDeviceNo())); + + return FeUtil.post(FeUtil.REQ_URL, nvps); + } + + /** + * @Author: ZhuXiao + * @Description: 打印订单 + * @Date: 9:58 2021/7/7 + */ + public static String print(FePrinterParams fePrinterParams, String content) throws Exception { + + List nvps = FeUtil.genIsvParams(fePrinterParams); + nvps.add(new BasicNameValuePair("apiname", "Open_printMsg")); + nvps.add(new BasicNameValuePair("sn", fePrinterParams.getDeviceParams().getDeviceNo())); + nvps.add(new BasicNameValuePair("content",content)); + nvps.add(new BasicNameValuePair("times", StringUtils.defaultString(String.valueOf(fePrinterParams.getBizConfigParams().getPrintNum()), "1")));//打印联数 + + return FeUtil.post(FeUtil.REQ_URL, nvps); + } + + /** + * @Author: ZhuXiao + * @Description: 清空待打印订单 + * @Date: 9:59 2021/7/7 + */ + public static String clear(FePrinterParams fePrinterParams) throws Exception { + + List nvps = FeUtil.genIsvParams(fePrinterParams); + nvps.add(new BasicNameValuePair("apiname", "Open_delPrinterSqs")); + nvps.add(new BasicNameValuePair("sn", fePrinterParams.getDeviceParams().getDeviceNo())); + + return FeUtil.post(FeUtil.REQ_URL, nvps); + } + + + private static List genIsvParams(FePrinterParams fePrinterParams) { + List nvps = new ArrayList<>(); + nvps.add(new BasicNameValuePair("user", fePrinterParams.getProviderParams().getUser())); + String sTime = String.valueOf(DateKit.currentTimeMillis()/1000); + nvps.add(new BasicNameValuePair("stime", sTime)); + nvps.add(new BasicNameValuePair("sig", signature(fePrinterParams.getProviderParams().getUser(), fePrinterParams.getProviderParams().getUkey(), sTime))); + return nvps; + } + + private static String post(String url, List list) throws Exception { + + CloseableHttpClient httpClient = getHttpClient(); + + HttpPost post = new HttpPost(url); + + CloseableHttpResponse response = null; + JSONObject resJSON; + + post.setEntity(new UrlEncodedFormEntity(list, "utf-8")); + log.info("\n【飞鹅云打印请求】:{}", list.toString()); + + response = httpClient.execute(post); + int statecode = response.getStatusLine().getStatusCode(); + if(statecode == 200){ + HttpEntity httpentity = response.getEntity(); + if (httpentity != null){ + String result = EntityUtils.toString(httpentity); + log.info("\n【飞鹅云打印返回】:{}", result); + + if (StringUtils.isBlank(result)) { + return null; + } + + resJSON = JSONObject.parseObject(result); + if (resJSON.getIntValue("ret") != 0) { + throw new BizException(resJSON.getString("msg")); + } + + if (StringUtils.isBlank(resJSON.getString("data"))) { + resJSON.put("data", "success"); + } + return resJSON.getString("data"); + } + } + + return null; + + } + + private static CloseableHttpClient getHttpClient() { + + //通过POST请求,发送打印信息到服务器 + RequestConfig requestConfig = RequestConfig.custom() + .setSocketTimeout(30000)//读取超时 + .setConnectTimeout(30000)//连接超时 + .build(); + + return HttpClients.custom() + .setDefaultRequestConfig(requestConfig) + .build(); + } + + //生成签名字符串 + private static String signature(String user, String uKey, String sTime){ + return DigestUtils.sha1Hex(user + uKey + sTime); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/YlyPrinterService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/YlyPrinterService.java new file mode 100644 index 0000000..883a811 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/YlyPrinterService.java @@ -0,0 +1,178 @@ +package com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.device.DeviceParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.YlyParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter.sdk.RequestMethod; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 云打印厂商: 易联云 + * + * @author xiaoyu + * + * @date 2023/4/11 16:36 + */ +@Slf4j +@Service +public class YlyPrinterService implements IPrinterService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + YlyParams ylyParams = getParams(deviceParams); + // 设备信息 + YlyParams.DeviceParams printConfig = ylyParams.getDeviceParams(); + // 厂商信息 + YlyParams.ProviderParams providerParams = ylyParams.getProviderParams(); + + String content = ""; + // 打印内容 + String contentPrint = createMessage(payOrderInfo, providerParams); + + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + content = "039043"+AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+"032"; + }else { + content = getPayTypeCode(payOrderInfo.getWayCodeType()) + "041031"+AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+"032"; + } + + // 仅播报 + if (ylyParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_SPEAK) { + RequestMethod.getInstance().printIndex(providerParams, printConfig, content, payOrderInfo.getPayOrderId()); + } + // 仅打印 + else if (ylyParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_PRINT) { + RequestMethod.getInstance().printIndex(providerParams, printConfig, contentPrint, payOrderInfo.getPayOrderId()); + } + // 打印并播报 + else { + // 播报+打印结果 + content = content + contentPrint; + RequestMethod.getInstance().printIndex(providerParams, printConfig, content, payOrderInfo.getPayOrderId()); + } + + // 打印联数 + int printNum = ylyParams.getBizConfigParams().getPrintNum() != null ? ylyParams.getBizConfigParams().getPrintNum() : 1; + if (printNum > 1) { + // 遍历打印 + for (int i = 1; i < printNum; i++) { + RequestMethod.getInstance().printIndex(providerParams, printConfig, contentPrint, payOrderInfo.getPayOrderId()); + } + } + + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException {} + + @Override + public String addPrinter(JSONObject deviceParams) { + YlyParams ylyParams = getParams(deviceParams); + // 设备信息 + YlyParams.DeviceParams printConfig = ylyParams.getDeviceParams(); + // 厂商信息 + YlyParams.ProviderParams providerParams = ylyParams.getProviderParams(); + + // 解绑&取消授权 + RequestMethod.getInstance().printerDeletePrinter(providerParams, printConfig); + + // 绑定设备 + RequestMethod.getInstance().addPrinter(providerParams, printConfig); + + // 设置打印logo (配置参数不为空) + if (StringUtils.isNotEmpty(providerParams.getPrintSetIcon())) { + // logo删除 + RequestMethod.getInstance().printDeleteIcon(providerParams, printConfig); + // logo设置 + RequestMethod.getInstance().printSetIcon(providerParams, printConfig); + } + // 设置K8设备关键词 + if (StringUtils.isNotEmpty(providerParams.getKeywords())) { + JSONArray array = new JSONArray(); + array.add(providerParams.getKeywords()); + RequestMethod.getInstance().printerSetKeywords(providerParams, printConfig, "order_payment", "white_list", array.toJSONString()); + } + + return "success"; + } + + @Override + public String editPrinter(JSONObject deviceParams) { + addPrinter(deviceParams); + return "success"; + } + + @Override + public String clearPrinter(JSONObject deviceParams) { + YlyParams ylyParams = getParams(deviceParams); + // 设备信息 + YlyParams.DeviceParams printConfig = ylyParams.getDeviceParams(); + // 厂商信息 + YlyParams.ProviderParams providerParams = ylyParams.getProviderParams(); + // 调用 + RequestMethod.getInstance().printCancelAll(providerParams, printConfig); + return null; + } + + + private YlyParams getParams(JSONObject deviceParams) { + JSONObject params = new JSONObject(); + params.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + params.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + params.put("bizConfigParams", JSON.parseObject(deviceParams.getString("bizConfigParams"))); + return JSON.parseObject(params.toJSONString(), YlyParams.class); + } + + /** + * 支付方式 + */ + public static String getPayTypeCode(String wayCodeType) { + if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { // 微信 + return "033"; + }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { // 支付宝 + return "034"; + }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(wayCodeType)) { // 云闪付 + return "050"; + }else { + return ""; + } + } + + /** + * 根据订单 生成云打印机打印内容 + * + * */ + public String createMessage(PayOrderInfo4Device printPayOrderInfo, YlyParams.ProviderParams providerParams) { + + String payOrderId = printPayOrderInfo.getPayOrderId(); + + // 标签说明: + // 文档地址:https://www.kancloud.cn/ly6886/oauth-api/3170341 + + // 门店名称 + String storeName = providerParams.getKeywords(); + storeName = StringUtils.isNotBlank(providerParams.getKeywords()) ? storeName : "计全科技"; + + // 打印内容 + String content = ""; + content = "
----------
\n"+ + ""+storeName+"\n\n" + + "下单时间: "+ DateUtil.format(printPayOrderInfo.getCreatedAt(), DatePattern.NORM_DATETIME_PATTERN)+"\n" + + "订单号: "+payOrderId+"\n" + + "订单金额: "+AmountUtil.convertCent2Dollar(printPayOrderInfo.getAmount())+"\n" + + "
----------
"; + return content; + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/HttpRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/HttpRequest.java new file mode 100644 index 0000000..c528103 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/HttpRequest.java @@ -0,0 +1,121 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// +package com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter.sdk; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +class HttpRequest { + HttpRequest() { + } + + public static String sendGet(String url, Map paramMap) { + String param = forMap(paramMap); + String result = ""; + BufferedReader in = null; + + try { + String urlNameString = url + "?" + param; + URLConnection connection = getUrlConnection(urlNameString); + connection.connect(); + Map> map = connection.getHeaderFields(); + Iterator var8 = map.keySet().iterator(); + + while(var8.hasNext()) { + String key = (String)var8.next(); + System.out.println(key + "--->" + map.get(key)); + } + + String line; + for(in = new BufferedReader(new InputStreamReader(connection.getInputStream())); (line = in.readLine()) != null; result = result + line) { + } + } catch (Exception var18) { + var18.printStackTrace(); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (Exception var17) { + var17.printStackTrace(); + } + + } + + return result; + } + + public static String sendPost(String url, Map paramMap) { + String param = forMap(paramMap); + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + + try { + URLConnection conn = getUrlConnection(url); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line; + while((line = in.readLine()) != null) { + result.append(line); + } + } catch (Exception var16) { + var16.printStackTrace(); + } finally { + try { + if (out != null) { + out.close(); + } + + if (in != null) { + in.close(); + } + } catch (IOException var15) { + var15.printStackTrace(); + } + + } + + return result.toString(); + } + + private static URLConnection getUrlConnection(String url) throws IOException { + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + conn.setConnectTimeout(30000); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + return conn; + } + + private static String forMap(Map paramMap) { + String reqStr = ""; + if (null != paramMap && !paramMap.isEmpty()) { + Entry entry; + for(Iterator var2 = paramMap.entrySet().iterator(); var2.hasNext(); reqStr = (String)entry.getKey() + "=" + (String)entry.getValue() + "&" + reqStr) { + entry = (Entry)var2.next(); + System.out.println("key = " + (String)entry.getKey() + ", value = " + (String)entry.getValue()); + } + + reqStr = reqStr.substring(0, reqStr.length() - 1); + } + + return reqStr; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/RequestMethod.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/RequestMethod.java new file mode 100644 index 0000000..8051d53 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/RequestMethod.java @@ -0,0 +1,728 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// +package com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter.sdk; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.YlyParams; +import lombok.extern.slf4j.Slf4j; + +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Slf4j +public class RequestMethod { + private static String example = "{\"error\":\"20\",\"error_description\":\"success\",\"body\":\"未完成初始化\"}"; + public String clientId; + public String clientSecret; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + private static final RequestMethod singleton = new RequestMethod(); + + public RequestMethod() { + } + + public static RequestMethod getInstance() { + return singleton; + } + + public void init(String client_id, String client_secret) { + clientId = client_id; + clientSecret = client_secret; + } + + private boolean CCIsNull(String client_id, String client_secret) { + return clientId != null && clientSecret != null && !clientId.equals("") && !clientSecret.equals(""); + } + + public String getCodeOpen(String redirect_uri) { + return clientId != null && !clientId.equals("") ? UtilUrl.openType + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + redirect_uri + "&state=1" : example; + } + + public String getOpenAccessToken(String code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("client_id", clientId); + paramMap.put("grant_type", "authorization_code"); + paramMap.put("sign", sign); + paramMap.put("code", code); + paramMap.put("scope", "all"); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + return HttpRequest.sendPost(UtilUrl.freeType, paramMap); + } else { + return example; + } + } + + public String getAccessToken() throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("client_id", clientId); + paramMap.put("grant_type", "client_credentials"); + paramMap.put("sign", sign); + paramMap.put("scope", "all"); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + return HttpRequest.sendPost(UtilUrl.freeType, paramMap); + } else { + return example; + } + } + + public String getRefreshAccessToken(String refresh_token) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("refresh_token", refresh_token); + paramMap.put("grant_type", "refresh_token"); + paramMap.put("scope", "all"); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.freeType, paramMap); + } else { + return example; + } + } + + public String addPrinter(String machine_code, String msign, String access_token) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("machine_code", machine_code); + paramMap.put("msign", msign); + paramMap.put("access_token", access_token); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.addPrinter, paramMap); + } else { + return example; + } + } + + public String addPrinter(String machine_code, String msign, String access_token, String phone, String print_name) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("machine_code", machine_code); + paramMap.put("msign", msign); + paramMap.put("access_token", access_token); + paramMap.put("phone", phone); + paramMap.put("print_name", print_name); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.addPrinter, paramMap); + } else { + return example; + } + } + + public String scanCodeModel(String machine_code, String msign) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("machine_code", machine_code); + paramMap.put("msign", msign); + paramMap.put("scope", "all"); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.scanCodeModel, paramMap); + } else { + return example; + } + } + + public String scanCodeModel_msign(String machine_code, String msign) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("machine_code", machine_code); + paramMap.put("msign", msign); + paramMap.put("scope", "all"); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.scanCodeModel, paramMap); + } else { + return example; + } + } + + public String printIndex(String access_token, String machine_code, String content, String origin_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("content", content); + paramMap.put("origin_id", origin_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("idempotence", "0"); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printIndex, paramMap); + } else { + return example; + } + } + + public String picturePrintIndex(String access_token, String machine_code, String picture_url, String origin_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("picture_url", URLEncoder.encode(picture_url, "UTF-8")); + paramMap.put("origin_id", origin_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.picturePrintIndex, paramMap); + } else { + return example; + } + } + + public String expressPrintIndex(String access_token, String machine_code, String content, String origin_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("content", content); + paramMap.put("origin_id", origin_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.expressPrintIndex, paramMap); + } else { + return example; + } + } + + public String printerSetVoice(String access_token, String machine_code, String content, String is_file, String aid, String origin_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("content", content); + paramMap.put("is_file", is_file); + paramMap.put("aid", aid); + paramMap.put("origin_id", origin_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerSetVoice, paramMap); + } else { + return example; + } + } + + public String printerDeleteVoice(String access_token, String machine_code, String aid, String origin_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("aid", aid); + paramMap.put("origin_id", origin_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerDeleteVoice, paramMap); + } else { + return example; + } + } + + public String printerDeletePrinter(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerDeletePrinter, paramMap); + } else { + return example; + } + } + + public String printMenuAddPrintMenu(String access_token, String machine_code, String content) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("content", content); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printMenuAddPrintMenu, paramMap); + } else { + return example; + } + } + + public String printShutdownRestart(String access_token, String machine_code, String response_type) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("response_type", response_type); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printShutdownRestart, paramMap); + } else { + return example; + } + } + + public String printSetSound(String access_token, String machine_code, String response_type, String voice) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("response_type", response_type); + paramMap.put("voice", voice); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printSetSound, paramMap); + } else { + return example; + } + } + + public String printPrintInfo(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printPrintInfo, paramMap); + } else { + return example; + } + } + + public String printGetVersion(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printGetVersion, paramMap); + } else { + return example; + } + } + + public String printCancelAll(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printCancelAll, paramMap); + } else { + return example; + } + } + + public String printCancelOne(String access_token, String machine_code, String order_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("order_id", order_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printCancelOne, paramMap); + } else { + return example; + } + } + + public String printSetIcon(String access_token, String machine_code, String img_url) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("img_url", img_url); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printSetIcon, paramMap); + } else { + return example; + } + } + + public String printDeleteIcon(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printDeleteIcon, paramMap); + } else { + return example; + } + } + + public String printBtnPrint(String access_token, String machine_code, String response_type) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("response_type", response_type); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printBtnPrint, paramMap); + } else { + return example; + } + } + + public String printGetOrder(String access_token, String machine_code, String response_type) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("response_type", response_type); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printGetOrder, paramMap); + } else { + return example; + } + } + + public String oauthSetPushUrl(String access_token, String machine_code, String cmd, String url, String status) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("cmd", cmd); + paramMap.put("url", url); + paramMap.put("status", status); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.oauthSetPushUrl, paramMap); + } else { + return example; + } + } + + public String printerGetOrderStatus(String access_token, String machine_code, String order_id) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("order_id", order_id); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerGetOrderStatus, paramMap); + } else { + return example; + } + } + + public String printerGetOrderPagingList(String access_token, String machine_code, String page_index, String page_size) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("page_index", page_index); + paramMap.put("page_size", page_size); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerGetOrderPagingList, paramMap); + } else { + return example; + } + } + + public String printerGetPrintStatus(String access_token, String machine_code) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerGetPrintStatus, paramMap); + } else { + return example; + } + } + + public String printerSetKeywords(String access_token, String machine_code, String keys, String type, String content) throws Exception { + if (CCIsNull(clientId, clientSecret)) { + String timestamp = Utils.getTimestamp(); + String signMD5 = clientId + timestamp + clientSecret; + String sign = Utils.getMD5Str(signMD5); + Map paramMap = new HashMap(); + paramMap.put("access_token", access_token); + paramMap.put("machine_code", machine_code); + paramMap.put("client_id", clientId); + paramMap.put("timestamp", timestamp); + paramMap.put("id", UUID.randomUUID().toString()); + paramMap.put("keys", keys); + paramMap.put("type", type); + paramMap.put("content", content); + paramMap.put("sign", sign); + return HttpRequest.sendPost(UtilUrl.printerSetKeywords, paramMap); + } else { + return example; + } + } + + /** 设备解绑 **/ + public String printerDeletePrinter(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + return createPost(UtilUrl.printerDeletePrinter, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** LOGO删除 **/ + public String printDeleteIcon(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + return createPost(UtilUrl.printDeleteIcon, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 设备绑定 **/ + public String addPrinter(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + paramMap.put("msign", printConfig.getDeviceKey()); + return createPost(UtilUrl.addPrinter, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 设置打印logo **/ + public String printSetIcon(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + paramMap.put("img_url", providerParams.getPrintSetIcon()); + return createPost(UtilUrl.printSetIcon, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 设备状态查询 **/ + public String printerGetPrintStatus(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + return createPost(UtilUrl.printerGetPrintStatus, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 配置关键词 **/ + public String printerSetKeywords(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig, String keys, String type, String content) { + try { + Map paramMap = new HashMap(); + paramMap.put("keys", keys); + paramMap.put("type", type); + paramMap.put("content", content); + return createPost(UtilUrl.printerSetKeywords, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 文本打印 **/ + public String printIndex(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig, String content, String origin_id) { + try { + Map paramMap = new HashMap(); + paramMap.put("content", content); + paramMap.put("origin_id", origin_id); + paramMap.put("idempotence", "0"); + return createPost(UtilUrl.printIndex, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 取消打印(全量) **/ + public String printCancelAll(YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + try { + Map paramMap = new HashMap(); + return createPost(UtilUrl.printCancelAll, paramMap, providerParams, printConfig); + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + /** 发送请求 **/ + public String createPost(String reqUrl, Map params, YlyParams.ProviderParams providerParams, YlyParams.DeviceParams printConfig) { + String timestamp = Utils.getTimestamp(); + String signMD5 = providerParams.getClientId() + timestamp + providerParams.getClientSecret(); + String sign = Utils.getMD5Str(signMD5); + + params.put("machine_code", printConfig.getDeviceNo()); + params.put("access_token", providerParams.getAccessToken()); + params.put("client_id", providerParams.getClientId()); + params.put("timestamp", timestamp); + params.put("id", UUID.randomUUID().toString()); + params.put("sign", sign); + + log.info("【易联云打印】-->>> 请求地址:{}, 请求参数:{}", reqUrl, params); + String result = HttpUtil.createPost(reqUrl).body(JSONObject.toJSONString(params)).execute().body(); + log.info("【易联云打印】-->>> 响应结果:{}", result); + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/UtilUrl.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/UtilUrl.java new file mode 100644 index 0000000..2b60727 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/UtilUrl.java @@ -0,0 +1,67 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// +package com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter.sdk; + +class UtilUrl { + public static String baseUrl = "https://open-api.10ss.net/v2/"; + public static String openType; + public static String freeType; + public static String addPrinter; + public static String scanCodeModel; + public static String printIndex; + public static String picturePrintIndex; + public static String expressPrintIndex; + public static String printerSetVoice; + public static String printerDeleteVoice; + public static String printerDeletePrinter; + public static String printMenuAddPrintMenu; + public static String printShutdownRestart; + public static String printSetSound; + public static String printPrintInfo; + public static String printGetVersion; + public static String printCancelAll; + public static String printCancelOne; + public static String printSetIcon; + public static String printDeleteIcon; + public static String printBtnPrint; + public static String printGetOrder; + public static String oauthSetPushUrl; + public static String printerGetOrderStatus; + public static String printerGetOrderPagingList; + public static String printerGetPrintStatus; + public static String printerSetKeywords; + + UtilUrl() { + } + + static { + openType = baseUrl + "oauth/authorize"; + freeType = baseUrl + "oauth/oauth"; + addPrinter = baseUrl + "printer/addprinter"; + scanCodeModel = baseUrl + "oauth/scancodemodel"; + printIndex = baseUrl + "print/index"; + picturePrintIndex = baseUrl + "pictureprint/index"; + expressPrintIndex = baseUrl + "expressprint/index"; + printerSetVoice = baseUrl + "printer/setvoice"; + printerDeleteVoice = baseUrl + "printer/deletevoice"; + printerDeletePrinter = baseUrl + "printer/deleteprinter"; + printMenuAddPrintMenu = baseUrl + "printmenu/addprintmenu"; + printShutdownRestart = baseUrl + "printer/shutdownrestart"; + printSetSound = baseUrl + "printer/setsound"; + printPrintInfo = baseUrl + "printer/printinfo"; + printGetVersion = baseUrl + "printer/getversion"; + printCancelAll = baseUrl + "printer/cancelall"; + printCancelOne = baseUrl + "printer/cancelone"; + printSetIcon = baseUrl + "printer/seticon"; + printDeleteIcon = baseUrl + "printer/deleteicon"; + printBtnPrint = baseUrl + "printer/btnprint"; + printGetOrder = baseUrl + "printer/getorder"; + oauthSetPushUrl = baseUrl + "oauth/setpushurl"; + printerGetOrderStatus = baseUrl + "printer/getorderstatus"; + printerGetOrderPagingList = baseUrl + "printer/getorderpaginglist"; + printerGetPrintStatus = baseUrl + "printer/getprintstatus"; + printerSetKeywords = baseUrl + "printer/setkeywords"; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/Utils.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/Utils.java new file mode 100644 index 0000000..bd62fb3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/ylyPrinter/sdk/Utils.java @@ -0,0 +1,52 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// +package com.jeequan.jeepay.thirdparty.device.printer.ylyPrinter.sdk; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class Utils { + public Utils() { + } + + public static String getMD5Str(String str) { + String re = null; + + try { + byte[] tem = str.getBytes(); + MessageDigest md5 = MessageDigest.getInstance("md5"); + md5.reset(); + md5.update(tem); + byte[] encrypt = md5.digest(); + StringBuilder sb = new StringBuilder(); + byte[] var6 = encrypt; + int var7 = encrypt.length; + + for(int var8 = 0; var8 < var7; ++var8) { + byte t = var6[var8]; + String s = Integer.toHexString(t & 255); + if (s.length() == 1) { + s = "0" + s; + } + + sb.append(s); + } + + re = sb.toString(); + } catch (NoSuchAlgorithmException var11) { + var11.printStackTrace(); + } + + return re.length() == 31 ? "0" + re : re; + } + + public static boolean isNull(String content) { + return content == null || content.equals(""); + } + + public static String getTimestamp() { + return String.valueOf(System.currentTimeMillis() / 1000L); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlPrinterService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlPrinterService.java new file mode 100644 index 0000000..6b78e8c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlPrinterService.java @@ -0,0 +1,218 @@ +package com.jeequan.jeepay.thirdparty.device.printer.zgwlPrinter; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.device.DeviceParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.ZgwlParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.device.speaker.zgwlSpeaker.ZgwlSpeakerService; +import com.jeequan.jeepay.thirdparty.device.speaker.zgwlSpeaker.util.ConnectionOptionWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.stereotype.Service; + +/* +* 云打印厂商: 智谷物联 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class ZgwlPrinterService implements IPrinterService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device printPayOrderInfo) { + + try { + // 智谷物联参数 + ZgwlParams zgwlParams = getZgwlParams(deviceParams); + + // 消息体 + byte[] message = createMessage(zgwlParams, printPayOrderInfo); + log.info("设备topic:{},消息:{}", zgwlParams.getProviderParams().getTopic(), message); + + String clientId = zgwlParams.getProviderParams().getGroupId() + "@@@" + zgwlParams.getDeviceParams().getDeviceNo(); + + // 发送消息 + sendMessage(zgwlParams.getProviderParams().getInstanceId(), zgwlParams.getProviderParams().getEndPoint(), zgwlParams.getProviderParams().getAccessKeyId(), + zgwlParams.getProviderParams().getAccessKeySecret(), clientId, zgwlParams.getProviderParams().getTopic(), message); + + }catch (Exception e) { + log.error("智谷物联推送失败", e); + throw new BizException(e.getMessage()); + } + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + ZgwlParams zgwlParams = getZgwlParams(deviceParams); + + // 设置播报、打印并播报才执行自定义播报 + if (zgwlParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_SPEAK || zgwlParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_PRINT_AND_SPEAK) { + ZgwlSpeakerService speakerService = SpringBeansUtil.getBean(ZgwlSpeakerService.class); + speakerService.sendCustomMsg(deviceParams, payOrderInfo); + }else { + throw new BizException("打印机未设置播报模式"); + } + } + + @Override + public String addPrinter(JSONObject deviceParams) { + return null; + } + + @Override + public String editPrinter(JSONObject deviceParams) { + return null; + } + + @Override + public String clearPrinter(JSONObject deviceParams) { + return null; + } + + + /** + * 根据订单 生成云打印机播报内容 + * 支付播报格式: 云打印机设备号|1007|交易单号|金额(元)|支付类型 + * 支付类型定义:2000-收款,2001-支付宝,2002-QQ,2003-微信,2004-京东,2005-银联,支持7571-7579自定义(自定义需要同时写入设备,如:7571-会员卡) + * */ + public byte[] createMessage(ZgwlParams zgwlParams, PayOrderInfo4Device printPayOrderInfo) { + + //支付方式 + int payTypeCode = getPayTypeCode(printPayOrderInfo.getIfCode()); + + String amount = ZgwlUtil.covertMoney(printPayOrderInfo.getAmount()); + + //打印文本 + String printText = "订单号:" + printPayOrderInfo.getPayOrderId(); + printText += "\r\n订单金额:" + amount; + printText += "\r\n下单时间:" + DateUtil.format(printPayOrderInfo.getCreatedAt(), DatePattern.NORM_DATETIME_FORMAT); + printText += "\r\n\r\n\r\n\r\n\r\n"; + + // 打印联数 + int printNum = zgwlParams.getBizConfigParams().getPrintNum() != null ? zgwlParams.getBizConfigParams().getPrintNum() : 1; + if (zgwlParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_PRINT) { + + return ZgwlUtil.getPrinterBytes(printText, printNum, ""); + + }else if (zgwlParams.getBizConfigParams().getPrintMode() == DeviceParams.MODE_SPEAK) { + + return ZgwlUtil.getStaticVoiceBytes(zgwlParams.getDeviceParams().getDeviceNo(), printPayOrderInfo.getPayOrderId(), amount, payTypeCode); + + }else { + + return ZgwlUtil.getPrinterVoiceBytes(printText, printNum, "" , zgwlParams.getDeviceParams().getDeviceNo(), + printPayOrderInfo.getPayOrderId(), amount, payTypeCode); + } + + } + + + /** + * 发送消息 + */ + public void sendMessage(String instanceId, String endPoint, String accessKey, String secretKey, String clientId, + String parentTopic, byte[] message) throws Exception { + + /** + * QoS参数代表传输质量,根据设备对接协议设定 + */ + final int qosLevel = 0; + //发送端ClientID,请勿与TOPIC中ClientID重复, + String masterClientId= clientId + StrUtil.subSufByLength(clientId, 6); + + ConnectionOptionWrapper connectionOptionWrapper = new ConnectionOptionWrapper(instanceId, accessKey, secretKey, masterClientId); + final MemoryPersistence memoryPersistence = new MemoryPersistence(); + /** + * 客户端使用的协议和端口必须匹配,具体参考文档 https://help.aliyun.com/document_detail/44866.html?spm=a2c4g.11186623.6.552.25302386RcuYFB + */ + final MqttClient mqttClient = new MqttClient("tcp://" + endPoint + ":1883", masterClientId, memoryPersistence); + /** + * 客户端设置好发送超时时间,防止无限阻塞 + */ + mqttClient.setTimeToWait(5000); + mqttClient.setCallback(new MqttCallbackExtended() { + @Override + public void connectComplete(boolean reconnect, String serverURI) { + /** + * 客户端连接成功后就需要尽快订阅需要的 topic + */ + log.info("Mqtt connect success"); + } + @Override + public void connectionLost(Throwable throwable) { + log.info("Mqtt connect lost"); + throwable.printStackTrace(); + } + @Override + public void messageArrived(String s, MqttMessage mqttMessage) throws Exception { + /** + * 消费消息的回调接口,需要确保该接口不抛异常,该接口运行返回即代表消息消费成功。 + * 消费消息需要保证在规定时间内完成,如果消费耗时超过服务端约定的超时时间,对于可靠传输的模式,服务端可能会重试推送,业务需要做好幂等去重处理。超时时间约定参考限制 + * https://help.aliyun.com/document_detail/63620.html?spm=a2c4g.11186623.6.546.229f1f6ago55Fj + */ + + log.info("receive msg from topic {} , body is {}", s, new String(mqttMessage.getPayload())); + } + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + log.info("send msg succeed topic is : {}", iMqttDeliveryToken.getTopics()[0]); + } + }); + mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions()); + /** + * MQ4IoT支持点对点消息,点对点消息不需要经过订阅关系匹配。点对点消息的 topic 格式是 {{parentTopic}}/p2p/{{targetClientId}} + */ + final String p2pSendTopic = parentTopic + "/p2p/" + clientId; + MqttMessage mqttMessage = new MqttMessage(message); + mqttMessage.setQos(qosLevel); + mqttClient.publish(p2pSendTopic, mqttMessage); + } + + private ZgwlParams getZgwlParams(JSONObject deviceParams){ + + JSONObject bsjJSON = new JSONObject(); + bsjJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + bsjJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + bsjJSON.put("bizConfigParams", JSON.parseObject(deviceParams.getString("bizConfigParams"))); + + // 智谷物联云喇叭参数 + return JSON.parseObject(bsjJSON.toJSONString(), ZgwlParams.class); + } + + /** + * 支付方式 + */ + private int getPayTypeCode(String ifCode) { + if (StringUtils.isBlank(ifCode)) { + return 2000; + } + + if (CS.IF_CODE.WXPAY.equals(ifCode)) { + return 2003; + }else if (CS.IF_CODE.ALIPAY.equals(ifCode)) { + return 2001; + }else if (CS.IF_CODE.YSFPAY.equals(ifCode)) { + return 2005; + }else { + return 2000; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlUtil.java new file mode 100644 index 0000000..f9b17e5 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zgwlPrinter/ZgwlUtil.java @@ -0,0 +1,145 @@ +package com.jeequan.jeepay.thirdparty.device.printer.zgwlPrinter; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/5 +*/ +public class ZgwlUtil { + + /** 金额转元,并去掉多余0 */ + public static String covertMoney(Long amount) { + return new BigDecimal(String.valueOf(amount)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString(); + } + + /** + * 获取打印内容 + * @param printText 打印文本 + * @param pageCount 打印联数 + * @param encodingStr 编码方式,默认UTF-8 + * @return + */ + public static byte[] getPrinterBytes(final String printText, + final int pageCount, String encodingStr) { + try { + if(encodingStr.equals("")){ + encodingStr="UTF-8"; + } + byte[] msgByte = printText.getBytes(encodingStr); + // 消息数组 + final byte[] dataByte = new byte[msgByte.length + 9]; + dataByte[0] = 0x1E; + dataByte[1] = 0x10; + dataByte[2] = (byte) pageCount;// 打印多联 + // 有效数据长度 + final int len = dataByte.length - 5; + dataByte[3] = (byte) (len >> 8); + dataByte[4] = (byte) (len & 0xff); + // 数据内容 + System.arraycopy(msgByte, 0, dataByte, 5, msgByte.length); + // 标识字节 + dataByte[dataByte.length - 4] = 0x1b; + dataByte[dataByte.length - 3] = 0x63; + // 打印内容CRC校验 + final byte[] dtCRC = getCRC(msgByte); + dataByte[dataByte.length - 2] = (byte) (dtCRC[0]); + dataByte[dataByte.length - 1] = (byte) (dtCRC[1]); + msgByte = dataByte; + return msgByte; + } catch (Exception ex) { + System.out.println(ex.getStackTrace()); + } + return null; + } + + /** + * 支付播报固定语音字节数组 + */ + public static byte[] getStaticVoiceBytes(String imeiStr,String msgId,String moneyStr,int payType){ + return getStaticVoiceStr(imeiStr,msgId,moneyStr,payType).getBytes(); + } + + /** + * 支付播报固定语音字符串 + */ + public static String getStaticVoiceStr(String imeiStr,String msgId,String moneyStr,int payType){ + String str = imeiStr+"|1007|"+msgId+"|"+moneyStr+"|"+payType; + return str; + } + + public static byte[] getPrinterVoiceBytes(String printTxt,int pageCount,String encodingStr,String imeiStr,String msgId,String moneyStr,int payType){ + byte[] voiceArray=getStaticVoiceBytes(imeiStr, msgId, moneyStr, payType); + byte[] printerArray=getPrinterBytes(printTxt,pageCount,encodingStr); + byte[] data=new byte[voiceArray.length+printerArray.length]; + System.arraycopy(printerArray, 0, data, 0, printerArray.length); + System.arraycopy(voiceArray, 0, data, printerArray.length, voiceArray.length); + return data; + } + + private static int[] CRC16Table = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, + 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, + 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, + 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, + 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, + 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, + 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, + 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, + 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, + 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, + 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, + 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, + 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, + 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, + 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, + 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, + 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, + 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, + 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, + 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, + 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, + 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, + 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, + 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, + 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, + 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, + 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, + 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, + 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, + 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, + 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, + 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, + 0x2c6a, 0x1ef1, 0x0f78 }; + + private static byte[] getCRC(byte[] bytes) { + int crc = 0xFFFF; // 初始值 + for (byte b : bytes) { + crc = (crc >> 8) ^ CRC16Table[(crc ^ b) & 0xff]; + } + byte[] b = new byte[2]; + b[0] = (byte) ((crc >> 8)^0xff); + b[1] = (byte) ((crc & 0xff)^0xff); + return b; + } + + private static final char[] HEXES = { '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + /** + * byte数组 转换成 16进制小写字符串 + */ + public static String bytes2Hex(byte[] bytes) { + if (bytes == null || bytes.length == 0) { + return null; + } + StringBuilder hex = new StringBuilder(); + for (byte b : bytes) { + hex.append(HEXES[(b >> 4) & 0x0F]); + hex.append(HEXES[b & 0x0F]); + } + return hex.toString(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zwPrinter/ZwPrinterService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zwPrinter/ZwPrinterService.java new file mode 100644 index 0000000..dd68af3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/printer/zwPrinter/ZwPrinterService.java @@ -0,0 +1,206 @@ +package com.jeequan.jeepay.thirdparty.device.printer.zwPrinter; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.IPrinterService; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.ZwParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.zw.model.request.PrintContextRequest; +import com.jeequan.jeepay.thirdparty.service.zw.model.request.PrintRequest; +import com.jeequan.jeepay.thirdparty.service.zw.model.request.UpdatePayParamRequest; +import com.jeequan.jeepay.thirdparty.service.zw.model.response.BaseResponse; +import com.jeequan.jeepay.thirdparty.service.zw.uils.SmartLinkUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 云打印厂商: 智网 + * + * @author xiaoyu + * @date 2023/4/11 16:36 + */ +@Slf4j +@Service +public class ZwPrinterService implements IPrinterService { + + @Autowired private SysConfigService sysConfigService; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + ZwParams zwParams = getZwParams(deviceParams); + PrintRequest request = new PrintRequest(); + request.setIndex(IdUtil.fastSimpleUUID()); + request.setSn(zwParams.getDeviceParams().getDeviceNo()); + request.setToken(zwParams.getProviderParams().getToken()); + + // 打印联数 + int printNum = zwParams.getBizConfigParams().getPrintNum() != null ? zwParams.getBizConfigParams().getPrintNum() : 1; + + PrintContextRequest contextRequest = new PrintContextRequest(); + // 音箱播报内容 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + contextRequest.setSc("会员余额支付" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + }else if (StringUtils.isNotBlank(zwParams.getProviderParams().getCustomContent())){ + contextRequest.setSc(zwParams.getProviderParams().getCustomContent() + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + } + + // 打印内容 + contextRequest.setPd(SmartLinkUtil.getPrintPd(payOrderInfo)); + // 打印联数 + contextRequest.setCn(printNum + ""); + request.setContext(contextRequest); + + BaseResponse response = SmartLinkUtil.cloudPrint(request); + if (!response.isSuccess()) { + throw new BizException(response.getErrmsg()); + } + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + ZwParams zwParams = getZwParams(deviceParams); + + PrintRequest request = new PrintRequest(); + request.setIndex(IdUtil.fastSimpleUUID()); + request.setSn(zwParams.getDeviceParams().getDeviceNo()); + request.setToken(zwParams.getProviderParams().getToken()); + + PrintContextRequest contextRequest = new PrintContextRequest(); + // 音箱播报内容 + contextRequest.setCn(zwParams.getProviderParams().getCustomContent() + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + // 打印内容 + contextRequest.setPd(SmartLinkUtil.getPrintPd(payOrderInfo)); + request.setContext(contextRequest); + + BaseResponse response = SmartLinkUtil.cloudPrint(request); + if (!response.isSuccess()) { + throw new BizException(response.getErrmsg()); + } + } + + @Override + public String addPrinter(JSONObject deviceParams) { + + ZwParams zwParams = getZwParams(deviceParams); + + ZwParams.DeviceParams printConfig = zwParams.getDeviceParams(); + // 参数校验 + checkConfigInfo(printConfig); + + UpdatePayParamRequest request = new UpdatePayParamRequest(); + request.setIndex(IdUtil.fastSimpleUUID()); + request.setSn(zwParams.getDeviceParams().getDeviceNo()); + request.setToken(zwParams.getProviderParams().getToken()); + request.setShopid("1"); + request.setTermid("zw"); + + request.setBill_cap(printConfig.getBillCap()); + request.setBill_print(printConfig.getBillPrint()); + request.setUrl(sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/zw/pay"); + request.setUrl_query(sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/zw/query"); + request.setBill_timeout(printConfig.getBillTimeout()); + request.setQuery_interval(printConfig.getQueryInterval()); + request.setQuery_num(printConfig.getQueryNum()); + request.setMd5key(zwParams.getProviderParams().getMd5Key()); + + if ("-1".equals(printConfig.getProviderCode())) { + request.setKeyword_cap(printConfig.getKeywordCap()); + request.setKeyword_skip(printConfig.getKeywordSkip()); + request.setOrder_prefix(printConfig.getOrderPrefix()); + request.setOrder_skip(printConfig.getOrderSkip()); + }else { + request.setPreset_prefix(printConfig.getPresetPrefix()); + request.setPreset_data(printConfig.getPresetData()); + request.setPreset_timestamp(printConfig.getTimestamp()); + } + request.setAuthcode(printConfig.getAuthCode()); + request.setErrinfo_print(printConfig.getErrInfoPrint()); + request.setRefundcode_print(printConfig.getRefundCodePrint()); + + // 支付方式 1-被扫 2-主扫 (默认为被扫) + request.setPay_mode(1); + +// request.setKeyword_cap("实收,应收,总价,总计,合计,订单总额"); +// request.setKeyword_skip("店名,销售商品报表"); + + BaseResponse response = SmartLinkUtil.updatePayParam(request); + if (!response.isSuccess()) { + log.error(response.getErrmsg()); + throw new BizException(response.getErrmsg()); + } + return "success"; + } + + @Override + public String editPrinter(JSONObject deviceParams) { + return null; + } + + @Override + public String clearPrinter(JSONObject deviceParams) { + return null; + } + + + private ZwParams getZwParams(JSONObject deviceParams) { + JSONObject zwJSON = new JSONObject(); + zwJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + zwJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + zwJSON.put("bizConfigParams", JSON.parseObject(deviceParams.getString("bizConfigParams"))); + return JSON.parseObject(zwJSON.toJSONString(), ZwParams.class); + } + + /** 设备参数校验 **/ + public void checkConfigInfo(ZwParams.DeviceParams printConfig) { + if (printConfig == null) { + throw new BizException("打印机参数配置不能为空"); + } + + if (StringUtils.isEmpty(printConfig.getAuthCode())) { + throw new BizException("16字节唯一验证码不能为空"); + } + + if (StringUtils.isEmpty(printConfig.getProviderCode())) { + throw new BizException("厂商编码不能为空"); + } + + if ("-1".equals(printConfig.getProviderCode())) { + + if (StringUtils.isEmpty(printConfig.getKeywordCap())) { + throw new BizException("获取收银小票支付金额关键字不能为空"); + } + if (StringUtils.isEmpty(printConfig.getKeywordSkip())) { + throw new BizException("小票放行关键字不能为空"); + } + if (printConfig.getOrderSkip() == null) { + throw new BizException("是否跳过重复的订单编号配置不能为空"); + } + }else { + if (StringUtils.isEmpty(printConfig.getPresetPrefix())) { + throw new BizException("收银小票金额拦截关键字不能为空"); + } + if (StringUtils.isEmpty(printConfig.getSoftCode())) { + throw new BizException("软件编号不能为空"); + } + if (StringUtils.isEmpty(printConfig.getSoftName())) { + throw new BizException("软件名称不能为空"); + } + if (StringUtils.isEmpty(printConfig.getTimestamp())) { + throw new BizException("时间戳不能为空"); + } + if (StringUtils.isEmpty(printConfig.getPresetData())) { + throw new BizException("支付预配置参数不能为空"); + } + + } + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjSpeakerService.java new file mode 100644 index 0000000..b469869 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjSpeakerService.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.bsjSpeaker; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.BsjParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* +* 云喇叭厂商: 博实结 +* +* @author zx +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class BsjSpeakerService implements ISpeakerService { + + private static final String REQ_URL = "https://ioe.car900.com/v1/openApi/dev/controlDevice.json"; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) { + + BsjParams bsjParams = getBsjParams(deviceParams); + JSONObject reqParams = BsjUtil.getSpeakData(bsjParams.getProviderParams().getCustomContent(), payOrderInfo); + + JSONObject resJSON = BsjUtil.get(REQ_URL, bsjParams, reqParams); + + if (resJSON == null) { + throw new BizException("请求失败"); + } + if (resJSON.getIntValue("code") != 0) { + throw new BizException(resJSON.getString("msg")); + } + } + + private BsjParams getBsjParams(JSONObject deviceParams) { + JSONObject bsjJSON = new JSONObject(); + bsjJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + bsjJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + return JSON.parseObject(bsjJSON.toJSONString(), BsjParams.class); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjUtil.java new file mode 100644 index 0000000..3785ce1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/bsjSpeaker/BsjUtil.java @@ -0,0 +1,180 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.bsjSpeaker; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.BsjParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.TreeMap; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/6 +*/ +@Slf4j +public class BsjUtil { + + /** + * 发起get请求 + */ + public static JSONObject get(String reqUrl, BsjParams bsjParams, JSONObject reqParams) throws BizException { + + packageCommonParams(bsjParams, reqParams); + + // 发起请求 + log.info("博实结设备号:{},请求参数:{}", bsjParams.getDeviceParams().getDeviceNo(), reqParams.toJSONString()); + String responseStr = HttpUtil.get(reqUrl, reqParams, 60000); + log.info("博实结设备号:{},返回结果:{}", bsjParams.getDeviceParams().getDeviceNo(), responseStr); + + if (StringUtils.isBlank(responseStr)) { + throw new BizException("请求失败"); + } + + return JSONObject.parseObject(responseStr); + } + + /** + * 发起post请求 + */ + public static JSONObject post(String reqUrl, BsjParams bsjParams, JSONObject reqParams) throws BizException { + + // 添加公共参数 + packageCommonParams(bsjParams, reqParams); + + // 发起请求 + log.info("博实结设备号:{},请求参数:{}", bsjParams.getDeviceParams().getDeviceNo(), reqParams.toJSONString()); + String responseStr = HttpUtil.post(reqUrl, reqParams, 60000); + log.info("博实结设备号:{},返回结果:{}", bsjParams.getDeviceParams().getDeviceNo(), responseStr); + + if (StringUtils.isBlank(responseStr)) { + throw new BizException("请求失败"); + } + + return JSONObject.parseObject(responseStr); + } + + /** 获取播报内容 bizType:1-交易语音 2-自定义语音 */ + public static JSONObject getSpeakData(String customContent, PayOrderInfo4Device payOrderInfo) { + JSONObject voiceJson = new JSONObject(); + + // 防逃单播报走自定义模式 + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("bizType", "2"); + voiceJson.put("content", "客户取消付款" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + return voiceJson; + } + + // 会员余额支付 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("bizType", "2"); + voiceJson.put("content", "会员余额支付" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + return voiceJson; + } + + // 配置了自定义播报内容 + if (StringUtils.isNotBlank(customContent)) { + voiceJson.put("bizType", "2"); + voiceJson.put("content", customContent + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + }else { + // 未配置 自定义播报内容,走默认播报语音 + voiceJson.put("bizType", "1"); + voiceJson.put("money", covertMoney(payOrderInfo.getAmount())); // 金额 + voiceJson.put("broadCastType", getPayTypeCode(payOrderInfo.getWayCodeType())); //1-收款成功 2-支付宝收款成功 3-微信收款成功 + } + + return voiceJson; + } + + private static JSONObject packageCommonParams(BsjParams bsjParams, JSONObject reqParams) { + reqParams.put("appId", bsjParams.getProviderParams().getAppId()); + reqParams.put("timestamp", DateKit.currentTimeMillis()); + reqParams.put("userCode", bsjParams.getProviderParams().getUserCode()); + reqParams.put("requestId", IdUtil.fastSimpleUUID()); //请求ID 唯一 + reqParams.put("token", getToken(reqParams, bsjParams.getProviderParams().getAppSecret())); + reqParams.put("devName", bsjParams.getDeviceParams().getDeviceNo()); //设备名称 唯一 + + return reqParams; + } + + /** + * 生成签名字符串 + */ + public static String getToken(JSONObject params, String appSecret) throws BizException { + + TreeMap tree = new TreeMap<>(); + + // 1. 所有参数进行排序 + params.keySet().forEach(key -> { + switch (key) { + case "appId": + case "requestId": + case "timestamp": + case "userCode": + tree.put(key, params.get(key)); + break; + } + }); + + //2. 拼接为 key=value&形式 + StringBuffer stringBuffer = new StringBuffer(); + tree.keySet().forEach(key -> { + + if (tree.get(key) == null) { + return ; + } + if(StringUtils.isAnyEmpty(key, tree.get(key).toString())){ //空值, 不参与签名 + return ; + } + if("token".equals(key)){ //签名串, 不参与签名 + return ; + } + + stringBuffer.append(key).append(tree.get(key).toString()); + }); + + //3. 拼接appSecret + String signStr = stringBuffer.append(appSecret).toString(); + log.info("博实结【待加签字符串】:{}", signStr); + + String md5 = JeepayKit.md5(signStr, "UTF-8"); + if (StringUtils.isBlank(md5)) { + throw new BizException("博实结请求数据加密失败"); + } + + return md5.toUpperCase(); + } + + /** + * 支付方式 + */ + public static String getPayTypeCode(String wayCodeType) { + if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { // 微信 + return "2"; + }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { // 支付宝 + return "3"; + }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(wayCodeType)) { // 云闪付 + return "8"; + }else if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(wayCodeType)) { + return "24"; + }else { + return "1"; + } + } + + /** 金额转元,并去掉多余0 */ + public static String covertMoney(Long amount) { + return new BigDecimal(String.valueOf(amount)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdSpeakerService.java new file mode 100644 index 0000000..a35eae8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdSpeakerService.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.jsdSpeaker; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.JsdParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* +* 云喇叭厂商: 金士盾 +* +* @author xy +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class JsdSpeakerService implements ISpeakerService { + + private static final String REQ_URL = "http://139.224.51.127/push"; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) { + + JsdParams jsdParams = getJsdParams(deviceParams); + JSONObject reqParams = JsdUtil.getSpeakData(jsdParams.getProviderParams().getCustomContent(), payOrderInfo); + + JSONObject resJSON = JsdUtil.post(REQ_URL, jsdParams, reqParams); + + if (resJSON == null) { + throw new BizException("请求失败"); + } + if (resJSON.getIntValue("code") != 0) { + throw new BizException(resJSON.getString("msg")); + } + } + + private JsdParams getJsdParams(JSONObject deviceParams) { + JSONObject jsdJSON = new JSONObject(); + jsdJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + jsdJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + return JSON.parseObject(jsdJSON.toJSONString(), JsdParams.class); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdUtil.java new file mode 100644 index 0000000..7d431c0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/jsdSpeaker/JsdUtil.java @@ -0,0 +1,158 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.jsdSpeaker; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.JsdParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.Base64Utils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.util.TreeMap; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/6 +*/ +@Slf4j +public class JsdUtil { + + /** + * 发起get请求 + */ + public static JSONObject post(String reqUrl, JsdParams jsdParams, JSONObject reqParams) throws BizException { + + packageCommonParams(jsdParams, reqParams); + + // 发起请求 + log.info("金士盾设备号:{},请求地址:{},请求参数:{}", jsdParams.getDeviceParams().getDeviceNo(), reqUrl, reqParams.toJSONString()); + String responseStr = HttpUtil.createPost(reqUrl) + .header("accessKey", jsdParams.getProviderParams().getAccessKey()) + .body(reqParams.toJSONString()) + .timeout(60000) + .execute().body(); + log.info("金士盾设备号:{},返回结果:{}", jsdParams.getDeviceParams().getDeviceNo(), responseStr); + + if (StringUtils.isBlank(responseStr)) { + throw new BizException("请求失败"); + } + + return JSONObject.parseObject(responseStr); + } + + /** 获取播报内容 */ + public static JSONObject getSpeakData(String customContent, PayOrderInfo4Device payOrderInfo) { + JSONObject voiceJson = new JSONObject(); + + // 订单号 + voiceJson.put("orderNo", payOrderInfo.getPayOrderId()); + // 请求唯一值 + voiceJson.put("requestId", payOrderInfo.getPayOrderId()); + // 金额 + voiceJson.put("money", AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"")); + + + // 防逃单播报走自定义模式 + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("payType", "4"); + voiceJson.put("msg", "客户取消付款" + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"") + "元"); + return voiceJson; + } + + // 会员余额支付 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("payType", "4"); + voiceJson.put("msg", "会员支付" + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"") + "元"); + return voiceJson; + } + + // 配置了自定义播报内容 + if (StringUtils.isNotBlank(customContent)) { + voiceJson.put("payType", "4"); + voiceJson.put("msg", customContent + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"")+ "元"); + }else { + // 未配置 自定义播报内容,走默认播报语音 + voiceJson.put("payType", "4"); + voiceJson.put("msg", getPayContent(payOrderInfo.getWayCodeType(), payOrderInfo.getAmount())); + } + + return voiceJson; + } + + private static JSONObject packageCommonParams(JsdParams jsdParams, JSONObject reqParams) { + reqParams.put("deviceName", jsdParams.getDeviceParams().getDeviceNo()); //设备名称 唯一 + reqParams.put("sign", getSign(reqParams, jsdParams.getProviderParams().getAccessKeySecret())); + + return reqParams; + } + + /** + * 生成签名字符串 + */ + public static String getSign(JSONObject params, String appSecret) throws BizException { + + TreeMap tree = new TreeMap<>(); + + // 1. 所有参数进行排序 + params.keySet().forEach(key -> { + if (!"sign".equals(key) && StringUtils.isNotEmpty(params.get(key).toString())) { + tree.put(key, params.get(key)); + } + }); + + //2. 拼接为 key=value&形式 + String signStr = JeepayKit.genUrlParams(tree); + + //3. 拼接appSecret + log.info("金士盾【待加签字符串】:{}", signStr); + return generateHmacSHA256(signStr, appSecret); + } + + public static String generateHmacSHA256(String data, String key) { + String result = null; + try { + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(secretKey); + result = Base64Utils.encodeToString(mac.doFinal(data.getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * 支付方式 + */ + public static String getPayContent(String wayCodeType, Long amount) { + + // 分转元 + String amountStr = AmountUtil.convertCent2DollarShort(amount+"")+ "元"; + + if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { // 微信 + return "微信收款" + amountStr; + }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { // 支付宝 + return "支付宝收款" + amountStr; + }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(wayCodeType)) { // 云闪付 + return "云闪付收款" + amountStr; + }else { + return "收款" + amountStr; + } + } + + /** 金额转元,并去掉多余0 */ + public static String covertMoney(Long amount) { + return new BigDecimal(String.valueOf(amount)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsSpeakerService.java new file mode 100644 index 0000000..2dbefbb --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsSpeakerService.java @@ -0,0 +1,446 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker; + +import cn.com.sand.hmpay.util.StringUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.digest.HMac; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.crypto.digest.MD5; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.icbc.api.internal.apache.http.impl.cookie.S; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.device.BsjParams; +import com.jeequan.jeepay.core.model.device.LklsParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.thirdparty.channel.lklspay.LklspayKit; +import com.jeequan.jeepay.thirdparty.channel.lklspay.model.LklPayMethod; +import com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker.model.LklsBizSpeaker; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.units.qual.A; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/* +* 云喇叭厂商: 拉卡拉 +* @author cystal +* @date 2023/12/28 11:10 +*/ +@Slf4j +@Service +public class LklsSpeakerService implements ISpeakerService { + + /** + * 推送接口域名 + */ + public static final String API_REQ_DOMAIN = "https://iot.yunmazhineng.com"; + + /** + * 推送播报语音接口地址 + */ + public static final String SEND_URL = "/api/ym/iot/api/sendVoiceMsg"; + + /** + * 绑定成功消息推送 + */ + public static final String BIND_SUCCESS_URL = "/api/notify/bind"; + + /** + * 拉卡拉版本绑定的地址 + */ + public static final String lkl_VERSION_BIND_URL = "/api/v2/iot/cloud/device/activate"; + + /** + * 获取营销区域广告坐标的信息 + */ + public static final String GET_BOX_MARKET_AREA_ADVERT = "/syapi/ym/marketArea/findCoordinateInfo"; + + + /** + * 获取营销区域图片的信息 + */ + public static final String GET_BOX_MARKET_PIC_ADVERT = "/syapi/ym/marketArea/findMarketPic"; + + /** + * 设置营销区域的图片 + */ + public static final String SET_BOX_MARKET_PIC_ADVERT = "/syapi/ym/marketArea/setMarketPic"; + + + /** + * 设备最新投放结果 + */ + public static final String PREVIEW_BOX_MARKET_RESULT_ADVERT = "/syapi/ym/marketArea/findLaunchStatus"; + + + /** + * 批量查询最新投放结果 + */ + public static final String PREVIEW_BATCH_BOX_MARKET_RESULT_ADVERT = "/syapi/ym/marketArea/batchfindLaunchStatus"; + + + /** + * 查询活动码信息 + */ + public static final String GET_BOX_ACTIVITY_INFO = "/syapi/ym/marketArea/findByActivityMsg"; + + + /** + * 设置设备跑马灯 + */ + public static final String SET_BOX_MARQUEE_INFO_ADVERT = "/syapi/ym/marketArea/setMarqueeInfo"; + + + /** + * 获取设备跑马灯 + */ + public static final String GET_BOX_MARQUEE_INFO_ADVERT = "/syapi/ym/marketArea/findMarqueeInfo"; + + /** + * 获取设备收款码区域坐标 + */ + public static final String GET_BOX_PAY_CODE_INFO_ADVERT = "/syapi/ym/marketArea/findPayCodeInfo"; + + /** + * 设置收款码区域图片信息 + */ + public static final String SET_BOX_PAY_CODE_PIC_ADVERT = "/syapi/ym/marketArea/setPayCodePic"; + + + /** + * 获取收款码区域图片信息 + */ + public static final String GET_BOX_PAY_CODE_PIC_ADVERT = "/syapi/ym/marketArea/findPayCodePic"; + + + /** + * 获取设备支付后营销区域坐标 + */ + public static final String GET_BOX_PAY_RET_INFO_ADVERT = "/syapi/ym/marketArea/findPayRetInfo"; + + + /** + * 设置支付后营销区域图片信息 + */ + public static final String SET_BOX_PAY_RET_INFO_ADVERT = "/syapi/ym/marketArea/setPayRetPic"; + + + /** + * 获取支付后营销区域图片信息 + */ + public static final String GET_BOX_PAY_RET_PIC_ADVERT = "/syapi/ym/marketArea/findPayRetPic"; + + + @Autowired private DeviceProvideConfigService deviceProvideConfigService; + + @Autowired private MchStoreDeviceService mchStoreDeviceService; + + @Autowired private SysConfigService sysConfigService; + + @Autowired private MchStoreService mchStoreService; + + @Autowired private MchApplymentService mchApplymentService; + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = LklsUtil.getSpeakData(lklsParams, payOrderInfo); + String respBizData = LklsUtil.req(API_REQ_DOMAIN + SEND_URL,lklsParams, bizData); + } + + /** + * 绑定成功消息推送 + * @param deviceParams + * @param isVersion false 自收单版本 true 默认拉卡拉收单版本 + * @return + */ + @Override + public void bindSend(JSONObject deviceParams,boolean isVersion) { + LklsParams lklsParams = getLklsParams(deviceParams); + if(isVersion){ + MchStore store = mchStoreService.getById(lklsParams.getExtParams().getStoreId()); + if(store == null || StringUtils.isEmpty(store.getMchApplyId())){ + throw new BizException("门店信息异常或门店关联的商户信息异常"); + } + MchApplyment applyment = mchApplymentService.getById(store.getMchApplyId()); + if(applyment == null){ + throw new BizException("商户信息异常"); + } + if(MchApplyment.STATE_SUCCESS != applyment.getState()){ + throw new BizException("门店关联的商户信息还未入网完成"); + } + LklspayIsvParams isvParams = (LklspayIsvParams)configContextQueryService.queryIsvParams(applyment.getIsvNo(), applyment.getIfCode()); + JSONObject reqData = new JSONObject(); + reqData.put("merId",applyment.getChannelMchNo()); + JSONObject bizData = JSONObject.parseObject(applyment.getSuccResParameter()); + reqData.put("termId",bizData.getString("termNo")); + reqData.put("sn",lklsParams.getDeviceParams().getDeviceNo()); + reqData.put("businessType","1"); + reqData.put("shopName",store.getStoreName()); + reqData.put("source","LOAP"); + reqData.put("merOrgNo","964645"); +// String result = LklspayKit.reqMch(LklPayMethod.Api.DEVICE_SPEAKER_BOX_ACTIVATE_URL, isvParams, reqData); +// return result; + }else{ + JSONObject bizData = new JSONObject(4); + bizData.put("deviceSn",lklsParams.getDeviceParams().getDeviceNo()); + bizData.put("binding",lklsParams.getExtParams().getBindState()); + String result = LklsUtil.req(API_REQ_DOMAIN + BIND_SUCCESS_URL,lklsParams, bizData); +// return JSON.parseObject(result); + } + } + + private LklsParams getLklsParams(JSONObject deviceParams) { + JSONObject data = new JSONObject(); + data.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + data.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + data.put("extParams", JSON.parseObject(deviceParams.getString("extParams"))); + return JSON.parseObject(data.toJSONString(), LklsParams.class); + } + + /** + * 设备绑定查询 + * @param params + * @return + */ + @Override + public JSONObject bindQuery(JSONObject params) { + log.info("【拉卡拉音箱】绑定查询请求参数:{}",params.toString()); + DeviceProvideConfig config = deviceProvideConfigService.getOneByAppId(params.getString("appId")); + try { + LklsBizSpeaker bizData = preCheck(config,params); + JSONObject bizResult = new JSONObject(8); + MchStoreDevice deviceInfo = mchStoreDeviceService.getDeviceInfo(bizData.getDeviceSn(), config.getDeviceType(), config.getProvider()); + bizResult.put("binding",Integer.valueOf(deviceInfo.getBindState())); + return initResult(params,HttpStatus.OK.value(), "获取成功",bizResult); + }catch (BizException e){ + return initResult(params,ApiCodeEnum.CUSTOM_FAIL.getCode(), e.getMessage(),null); + } + } + + /** + * 初始化返回信息 + * @param params + * @param code + * @param msg + * @return + */ + private JSONObject initResult(JSONObject params,Integer code ,String msg,JSONObject bizData) { + if(bizData == null){ + bizData = new JSONObject(3); + } + bizData.put("code", code); + bizData.put("msg",msg); + params.put("reqData",Base64.encode(bizData.toString())); + return params; + } + + /** + * 设备获取url + * @param params + * @return + */ + @Override + public JSONObject getUrl(JSONObject params) { + log.info("【拉卡拉音箱】获取二维码请求参数:{}",params.toString()); + DeviceProvideConfig config = deviceProvideConfigService.getOneByAppId(params.getString("appId")); + try { + LklsBizSpeaker speaker = preCheck(config, params); + MchStoreDevice mchStoreDevice = mchStoreDeviceService.getDeviceInfo(speaker.getDeviceSn(), config.getDeviceType(), config.getProvider()); + if(mchStoreDevice == null){ + log.info("设备信息未找到,参数1:{},参数2:{},参数3:{}",speaker.getDeviceSn(),config.getDeviceType(),config.getProvider()); + return initResult(params,ApiCodeEnum.SYSTEM_ERROR.getCode(),"设备信息未找到",null); + } + MchApplyment mchApplyment = mchApplymentService.getById(mchStoreDevice.getMchApplyId()); + + JSONObject bizResult = new JSONObject(); + //如果是绑定的马牌 + String url = sysConfigService.getDBApplicationConfig().genUniJsapiPayUrl(QRCodeParams.TYPE_QRC_DEVICE, QRCodeParams.ENTRY_PAGE_LITE,mchStoreDevice.getDeviceId().toString(), mchApplyment.getIsvNo(),speaker.getAmount()); + bizResult.put("url",url); + Integer effectTime = speaker.getAmount() != null ? 30 : -1; + bizResult.put("effectTime",effectTime); + return initResult(params,HttpStatus.OK.value(), "获取成功",bizResult); + }catch (BizException e){ + return initResult(params,ApiCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage(),null); + } + } + + + private LklsBizSpeaker preCheck(DeviceProvideConfig config, JSONObject params) { + if(config == null){ + throw new BizException("未获取音箱厂家配置信息"); + } + String providerParams = config.getProviderParams(); + if(StringUtils.isEmpty(providerParams)){ + throw new BizException("音箱厂家基础配置信息为空"); + } + JSONObject paramsProviderConfig = JSON.parseObject(providerParams); + if(StringUtils.isEmpty(paramsProviderConfig.getString("appSecret"))){ + throw new BizException("音箱厂家密钥信息为空"); + } + checkSign(params,paramsProviderConfig.getString("appSecret")); + String reqData = params.getString("reqData"); + return JSON.parseObject(Base64.decodeStr(reqData),LklsBizSpeaker.class); + } + /** + *校验参数 + */ + public void checkSign(JSONObject params, String appSecret) { + String signType = params.getString("signType"); + String sign = params.getString("sign"); + String reqData = params.getString("reqData"); + String checkSign = null; + if("md5".equals(signType)){ + checkSign = SecureUtil.md5(reqData + appSecret); + }else if("HmacSHA256".equals(signType)){ + HMac hmac = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, appSecret); + checkSign = hmac.digestHex(reqData); + }else{ + throw new BizException("未知的签名类型"); + } + if(!checkSign.equals(sign)){ + throw new BizException("签名异常"); + } + } + + /** + * 获取营销区域的广告坐标信息 + * @param deviceParams + * @return + */ + public JSONObject getMarketAreaAdvert(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARKET_AREA_ADVERT, lklsParams, bizData); + return JSON.parseObject(bizResult); + } + + /** + * 设置营销区域的广告 + * @param deviceParams + * @param bizData + * @return + */ + public JSONObject setMarketAreaAdvert(JSONObject deviceParams,JSONObject bizData) { + LklsParams lklsParams = getLklsParams(deviceParams); + String bizResult = LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData); + return JSON.parseObject(bizResult); + } + + /** + * 获取设备跑马灯广告 + * @param deviceParams + * @return + */ + public JSONObject getMarqueeInfo(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + bizData.put("translsNo", SeqKit.genFlowNo("F")); + String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARQUEE_INFO_ADVERT, lklsParams, bizData); + return JSON.parseObject(bizResult); + } + + /** + * 设置跑马灯 + * @param deviceParams + * @param bizData + * @return + */ + public JSONObject setMarqueeInfo(JSONObject deviceParams,JSONObject bizData) { + LklsParams lklsParams = getLklsParams(deviceParams); + String bizResult = LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARQUEE_INFO_ADVERT, lklsParams, bizData); + return JSON.parseObject(bizResult); + } + + /** + * 获取营销区域的图片信息 + * @param deviceParams + * @return + */ + public JSONArray getMarketPic(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + String bizResult = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData); + return JSONArray.parseArray(bizResult); + } + + public void setMarketPic(JSONObject deviceParams, JSONObject bizData) { + LklsParams lklsParams = getLklsParams(deviceParams); + LklsUtil.req(API_REQ_DOMAIN + SET_BOX_MARKET_PIC_ADVERT, lklsParams, bizData); + } + + /** + * 查询设备活动码信息 + * @param deviceParams + * @return + */ + public JSONObject getActivityQrCode(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_ACTIVITY_INFO, lklsParams, bizData); + return JSON.parseObject(result); + } + + /** + * 获取设备付款区域坐标 + * @param deviceParams + * @return + */ + public JSONObject getMarketPayCodeInfo(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + bizData.put("translsNo",SeqKit.genFlowNo("F")); + String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_PAY_CODE_INFO_ADVERT, lklsParams, bizData); + return JSON.parseObject(result); + } + + /** + * 获取设备付款区域图片信息 + * @param deviceParams + * @return + */ + public JSONObject getMarketPayCodePic(JSONObject deviceParams) { + LklsParams lklsParams = getLklsParams(deviceParams); + JSONObject bizData = new JSONObject(); + bizData.put("devSn",lklsParams.getDeviceParams().getDeviceNo()); + bizData.put("translsNo",SeqKit.genFlowNo("F")); + String result = LklsUtil.req(API_REQ_DOMAIN + GET_BOX_PAY_CODE_PIC_ADVERT, lklsParams, bizData); + return JSON.parseObject(result); + } + + public void setMarketPayCodePic(JSONObject deviceParams, JSONObject bizData) { + LklsParams lklsParams = getLklsParams(deviceParams); + LklsUtil.req(API_REQ_DOMAIN + SET_BOX_PAY_CODE_PIC_ADVERT, lklsParams, bizData); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsUtil.java new file mode 100644 index 0000000..4c47586 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/LklsUtil.java @@ -0,0 +1,91 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.BsjParams; +import com.jeequan.jeepay.core.model.device.LklsParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; + +/** + * TODO + * 拉卡拉音箱发起请求 + * @author crystal + * @date 2023/12/28 17:41 + */ +@Slf4j +public class LklsUtil { + /** + * 发起请求 + * @param reqUrl + * @param lklsParams + * @param bizData + * @return + */ + public static String req(String reqUrl, LklsParams lklsParams, JSONObject bizData) { + log.info("【拉卡拉音箱】请求业务参数:{}",bizData); + JSONObject request = packageCommonParams(lklsParams, bizData); + log.info("【拉卡拉音箱】请求地址:{},请求参数:{}",reqUrl,request); + String response = HttpUtil.post(reqUrl, request.toString()); + log.info("【拉卡拉音箱】返回参数:{}",response); + if (StringUtils.isBlank(response)) { + throw new BizException("【拉卡拉音箱】播报接口请求失败"); + } + JSONObject respData = JSONObject.parseObject(response); + if(respData.getInteger("status") == null){ + return response; + } + if (respData.getIntValue("status") != HttpStatus.OK.value()) { + throw new BizException(respData.getString("message")); + } + if(StringUtils.isEmpty(respData.getString("data"))){ + return null; + } + String data = Base64.decodeStr(respData.getString("data")); + log.info("【拉卡拉音箱】返回参数,解密结果:{}",data); + return data; + } + + private static JSONObject packageCommonParams(LklsParams lklsParams, JSONObject bizData) { + JSONObject reqParams = new JSONObject(); + reqParams.put("appId", lklsParams.getProviderParams().getAppId()); + reqParams.put("signType", "md5"); + String base64BizData = Base64.encode(bizData.toString()); + reqParams.put("reqData",base64BizData); + reqParams.put("sign", SecureUtil.md5( base64BizData + lklsParams.getProviderParams().getAppSecret())); + return reqParams; + } + + public static JSONObject getSpeakData(LklsParams lklsParams, PayOrderInfo4Device payOrderInfo) { + JSONObject bizData = new JSONObject(); + bizData.put("sn",lklsParams.getDeviceParams().getDeviceNo()); + bizData.put("messageId",payOrderInfo.getPayOrderId()); + bizData.put("reqTimeStamp",System.currentTimeMillis()); + // 防逃单播报走自定义模式 + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + bizData.put("voiceMsg", "客户取消付款" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + return bizData; + } + // 会员余额支付 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + bizData.put("voiceMsg", "会员余额支付" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + return bizData; + } + // 配置了自定义播报内容 + if (StringUtils.isNotBlank(lklsParams.getProviderParams().getCustomContent())) { + bizData.put("voiceMsg", lklsParams.getProviderParams().getCustomContent() + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + }else { + bizData.put("voiceMsg", "收款成功" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + } + return bizData; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/model/LklsBizSpeaker.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/model/LklsBizSpeaker.java new file mode 100644 index 0000000..014c2fe --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/lklsSpeaker/model/LklsBizSpeaker.java @@ -0,0 +1,18 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.lklsSpeaker.model; + +import com.icbc.api.internal.apache.http.impl.cookie.S; +import lombok.Data; + +/** + * TODO + * 拉卡拉音箱业务参数 + * @author crystal + * @date 2023/12/28 14:44 + */ +@Data +public class LklsBizSpeaker { + + private String deviceSn; + + private Long amount; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznSpeakerService.java new file mode 100644 index 0000000..af5eee6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznSpeakerService.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.llznSpeaker; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.LlznParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/* +* 云喇叭厂商: 零零智能 +* +* @author xy +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class LlznSpeakerService implements ISpeakerService { + + private static final String REQ_URL = "https://pay-broadcast-api-test.rinlink.com/createVoiceBroadcast"; + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) { + + LlznParams params = getLlznParams(deviceParams); + JSONObject reqParams = LlznUtil.getSpeakData(params.getProviderParams().getCustomContent(), payOrderInfo); + + JSONObject resJSON = LlznUtil.post(REQ_URL, params, reqParams); + + if (resJSON == null) { + throw new BizException("请求失败"); + } + if (resJSON.getIntValue("code") != 0) { + throw new BizException(resJSON.getString("msg")); + } + } + + private LlznParams getLlznParams(JSONObject deviceParams) { + JSONObject jsdJSON = new JSONObject(); + jsdJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + jsdJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + return JSON.parseObject(jsdJSON.toJSONString(), LlznParams.class); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznUtil.java new file mode 100644 index 0000000..3029289 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/llznSpeaker/LlznUtil.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.llznSpeaker; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.LlznParams; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/6 +*/ +@Slf4j +public class LlznUtil { + + /** + * 发起get请求 + */ + public static JSONObject post(String reqUrl, LlznParams params, JSONObject reqParams) throws BizException { + + packageCommonParams(params, reqParams); + + // 发起请求 + log.info("零零智能设备号:{},请求地址:{},请求参数:{}", params.getDeviceParams().getDeviceNo(), reqUrl, reqParams.toJSONString()); + String responseStr = HttpUtil.createPost(reqUrl) + .header("api-key", params.getProviderParams().getApiKey()) + .body(reqParams.toJSONString()) + .timeout(60000) + .execute().body(); + log.info("零零智能设备号:{},返回结果:{}", params.getDeviceParams().getDeviceNo(), responseStr); + + if (StringUtils.isBlank(responseStr)) { + throw new BizException("请求失败"); + } + + return JSONObject.parseObject(responseStr); + } + + /** 获取播报内容 */ + public static JSONObject getSpeakData(String customContent, PayOrderInfo4Device payOrderInfo) { + JSONObject voiceJson = new JSONObject(); + + // 支付类型 1-在播放金额之前播放支付类型;2-自定义tts + voiceJson.put("biz_type", "2"); + // 1-成功收到付款(xx美元);2-支付宝;3-微信;4-银联;5-取消支付 +// voiceJson.put("broadcast_type", "1"); + // Qrcode=动态二维码网站,可以为空,如果不为空,支付二维码 将显示代码 +// voiceJson.put("qrcode", ""); + // 金额 + voiceJson.put("money", AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"")); + + + // 防逃单播报走自定义模式 + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("tts", "客户取消付款" + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"") + "元"); + return voiceJson; + } + + // 会员余额支付 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + voiceJson.put("tts", "会员支付" + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"") + "元"); + return voiceJson; + } + + // 配置了自定义播报内容 + if (StringUtils.isNotBlank(customContent)) { + voiceJson.put("tts", customContent + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"")+ "元"); + }else { + // 未配置 自定义播报内容,走默认播报语音 + voiceJson.put("tts", getPayContent(payOrderInfo.getWayCodeType(), payOrderInfo.getAmount())); + } + + return voiceJson; + } + + private static JSONObject packageCommonParams(LlznParams params, JSONObject reqParams) { + reqParams.put("deviceNumber", params.getDeviceParams().getDeviceNo()); //设备名称 唯一 + + return reqParams; + } + + + /** + * 支付方式 + */ + public static String getPayContent(String wayCodeType, Long amount) { + + // 分转元 + String amountStr = AmountUtil.convertCent2DollarShort(amount+"")+ "元"; + + if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { // 微信 + return "微信收款" + amountStr; + }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { // 支付宝 + return "支付宝收款" + amountStr; + }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(wayCodeType)) { // 云闪付 + return "云闪付收款" + amountStr; + }else { + return "收款" + amountStr; + } + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsSpeakerService.java new file mode 100644 index 0000000..0308e4b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsSpeakerService.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.psSpeaker; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.PsSpeakerParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* +* 云喇叭厂商: 品生 +* +* @author zx +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class PsSpeakerService implements ISpeakerService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + /*PsSpeakerParams psSpeakerParams = getPsSpeakerParams(deviceParams); + + speak(psSpeakerParams, payOrderInfo);*/ + + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + PsSpeakerParams psSpeakerParams = getPsSpeakerParams(deviceParams); + + JSONObject reqParams = new JSONObject(); + reqParams.put("devid", psSpeakerParams.getDeviceParams().getDeviceNo()); // 设备ID + reqParams.put("reqid", IdUtil.fastSimpleUUID()); // 请求ID + reqParams.put("time", DateUtil.format(payOrderInfo.getCreatedAt(), DatePattern.PURE_DATETIME_PATTERN)); + + if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + reqParams.put("message", "客户取消付款" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + }else if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + reqParams.put("message", "会员余额支付" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + }else { + // 未配置 自定义播报内容,走默认播报语音 + if (StringUtils.isBlank(psSpeakerParams.getProviderParams().getCustomContent())) { + speak(psSpeakerParams, payOrderInfo); + }else { + reqParams.put("message", psSpeakerParams.getProviderParams().getCustomContent() + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount())+ "元"); + } + } + + PsUtil.post("/message/sendMsg", reqParams, PsUtil.getToken(psSpeakerParams)); + } + + /** + * 发起请求 + */ + private JSONObject speak(PsSpeakerParams psSpeakerParams, PayOrderInfo4Device payOrderInfo) throws BizException { + + JSONObject reqParams = new JSONObject(); + reqParams.put("devid", psSpeakerParams.getDeviceParams().getDeviceNo()); // 设备ID + reqParams.put("reqid", IdUtil.fastSimpleUUID()); // 请求ID + reqParams.put("time", DateUtil.format(payOrderInfo.getCreatedAt(), DatePattern.PURE_DATETIME_PATTERN)); + reqParams.put("payment", payOrderInfo.getAmount()); // 金额,分 + reqParams.put("type", getPayTypeCode(payOrderInfo.getWayCodeType())); //1-收款成功 2-支付宝收款成功 3-微信收款成功 + + return PsUtil.post("/message/sendMsg", reqParams, PsUtil.getToken(psSpeakerParams)); + } + + private PsSpeakerParams getPsSpeakerParams(JSONObject deviceParams) { + JSONObject paramsJSON = new JSONObject(); + paramsJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + paramsJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + // 飞鹅云打印参数 + return JSON.parseObject(paramsJSON.toJSONString(), PsSpeakerParams.class); + } + + + /** + * 支付方式 + */ + private int getPayTypeCode(String wayCodeType) { + if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { // 支付宝 + return 2; + }else if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { // 微信 + return 3; + }else if (CS.PAY_WAY_CODE_TYPE.UNIONPAY.equals(wayCodeType)) { // 银联 + return 5; + }else { + return 1; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsUtil.java new file mode 100644 index 0000000..b7c0490 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/psSpeaker/PsUtil.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.psSpeaker; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.PsSpeakerParams; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.concurrent.TimeUnit; + +/** + * @Author: ZhuXiao + * @Description: + * @Date: 18:20 2021/7/6 +*/ +@Slf4j +public class PsUtil { + + private final static String REQ_URL = "https://open.zergiot.com/api"; + + /** + * 获取token + */ + public static String getToken(PsSpeakerParams psSpeakerParams) throws BizException { + + String cacheKey = CS.PINSHENG_TOKEN_CACHE_KEY + "_" + psSpeakerParams.getProviderParams().getUsername(); + String accessToken = RedisUtil.getString(cacheKey); + if (StringUtils.isNotBlank(accessToken)) { + return accessToken; + } + + JSONObject params = (JSONObject) JSONObject.toJSON(psSpeakerParams.getProviderParams()); + + JSONObject obj = post("/getToken", params, null); + if (obj == null) { + throw new BizException("请求异常,获取token失败"); + } + + accessToken = obj.getString("token"); + log.info("品生云喇叭获取token = {}", accessToken); + + //保存token + RedisUtil.setString(cacheKey, accessToken, CS.PINSHENG_TOKEN_TIME, TimeUnit.SECONDS); + + return accessToken; + } + + /** + * 发起post请求 + */ + public static JSONObject post(String reqUrl, JSONObject reqParams, String token) throws BizException { + + log.info("品生云喇叭请求参数 = {}", reqParams.toJSONString()); + HttpRequest httpRequest = HttpUtil.createPost(REQ_URL + reqUrl).header("token", token).contentType("application/json").timeout(60000); + String responseStr = httpRequest.body(reqParams.toJSONString()).execute().body(); + log.info("品生云喇叭响应response = {}", responseStr); + if (StringUtils.isBlank(responseStr)) { + throw new BizException("请求失败,响应结果为空"); + } + + JSONObject obj = JSONObject.parseObject(responseStr); + if (!"200".equals(obj.getString("code")) || !obj.getBoolean("success")) { + throw new BizException("请求失败,errCode:【" + obj.getString("code") + "】,errMsg:" + obj.getString("message")); + } + + return obj.getJSONObject("data"); + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/ZgwlSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/ZgwlSpeakerService.java new file mode 100644 index 0000000..890a2a0 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/ZgwlSpeakerService.java @@ -0,0 +1,186 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.zgwlSpeaker; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.ZgwlParams; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.thirdparty.device.printer.zgwlPrinter.ZgwlUtil; +import com.jeequan.jeepay.thirdparty.device.speaker.zgwlSpeaker.util.ConnectionOptionWrapper; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.stereotype.Service; + +/* +* 云喇叭厂商: 智谷物联 +* +* @author zhuxiao +* +* @date 2021/6/8 18:10 +*/ +@Slf4j +@Service +public class ZgwlSpeakerService implements ISpeakerService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) { + + try { + + // 智谷物联云喇叭参数 + ZgwlParams zgwlParams = getZgwlParams(deviceParams); + + // 消息体 + String message = createMessage(speakPayOrderInfo, zgwlParams.getDeviceParams().getDeviceNo()); + log.info("云喇叭topic:{},消息:{}", zgwlParams.getProviderParams().getTopic(), message); + + String clientId = zgwlParams.getProviderParams().getGroupId() + "@@@" + zgwlParams.getDeviceParams().getDeviceNo(); + + // 发送消息 + sendMessage(zgwlParams.getProviderParams().getInstanceId(), zgwlParams.getProviderParams().getEndPoint(), zgwlParams.getProviderParams().getAccessKeyId(), + zgwlParams.getProviderParams().getAccessKeySecret(), clientId, zgwlParams.getProviderParams().getTopic(), message.getBytes()); + + }catch (Exception e) { + log.error("智谷物联云音箱播报失败", e); + throw new BizException(e.getMessage()); + } + + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device speakPayOrderInfo) { + + try { + + // 智谷物联云喇叭参数 + ZgwlParams zgwlParams = getZgwlParams(deviceParams); + + // 消息体 + String message = createMessage(speakPayOrderInfo, zgwlParams.getDeviceParams().getDeviceNo()); + log.info("云喇叭topic:{},消息:{}", zgwlParams.getProviderParams().getTopic(), message); + + String clientId = zgwlParams.getProviderParams().getGroupId() + "@@@" + zgwlParams.getDeviceParams().getDeviceNo(); + + // 发送消息 + sendMessage(zgwlParams.getProviderParams().getInstanceId(), zgwlParams.getProviderParams().getEndPoint(), zgwlParams.getProviderParams().getAccessKeyId(), + zgwlParams.getProviderParams().getAccessKeySecret(), clientId, zgwlParams.getProviderParams().getTopic(), message.getBytes()); + + }catch (Exception e) { + log.error("智谷物联云音箱播报失败", e); + throw new BizException(e.getMessage()); + } + + } + + private ZgwlParams getZgwlParams(JSONObject deviceParams) { + JSONObject paramsJSON = new JSONObject(); + paramsJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + paramsJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + // 云打印参数 + return JSON.parseObject(paramsJSON.toJSONString(), ZgwlParams.class); + } + + /** + * 根据订单 生成云喇叭消息 + * 支付播报格式: 云喇叭设备号|1007|交易单号|金额(元)|支付类型 + * 支付类型定义:2000-收款,2001-支付宝,2002-QQ,2003-微信,2004-京东,2005-银联,支持7571-7579自定义(自定义需要同时写入设备,如:7571-会员卡) + * */ + private String createMessage(PayOrderInfo4Device speakPayOrderInfo, String deviceNo) { + //支付方式 + String payTypeCode = getPayTypeCode(speakPayOrderInfo.getWayCodeType()); + + final String separator = "|"; + + StringBuffer buffer = new StringBuffer(); + buffer.append(deviceNo).append(separator); + buffer.append("1007|"); + buffer.append(speakPayOrderInfo.getPayOrderId()).append(separator); + buffer.append(ZgwlUtil.covertMoney(speakPayOrderInfo.getAmount())).append(separator); + buffer.append(payTypeCode); + return buffer.toString(); + } + + public void sendMessage(String instanceId, String endPoint, String accessKey, String secretKey, String clientId, + String parentTopic, byte[] message) throws Exception { + + /** + * QoS参数代表传输质量,根据设备对接协议设定 + */ + final int qosLevel = 2; + //发送端ClientID,请勿与TOPIC中ClientID重复, + String masterClientId= clientId + DateKit.currentTimeMillis(); + + ConnectionOptionWrapper connectionOptionWrapper = new ConnectionOptionWrapper(instanceId, accessKey, secretKey, masterClientId); + final MemoryPersistence memoryPersistence = new MemoryPersistence(); + /** + * 客户端使用的协议和端口必须匹配,具体参考文档 https://help.aliyun.com/document_detail/44866.html?spm=a2c4g.11186623.6.552.25302386RcuYFB + */ + final MqttClient mqttClient = new MqttClient("tcp://" + endPoint + ":1883", masterClientId, memoryPersistence); + /** + * 客户端设置好发送超时时间,防止无限阻塞 + */ + mqttClient.setTimeToWait(5000); + mqttClient.setCallback(new MqttCallbackExtended() { + @Override + public void connectComplete(boolean reconnect, String serverURI) { + /** + * 客户端连接成功后就需要尽快订阅需要的 topic + */ + log.info("Mqtt connect success"); + } + @Override + public void connectionLost(Throwable throwable) { + log.info("Mqtt connect lost"); + throwable.printStackTrace(); + } + @Override + public void messageArrived(String s, MqttMessage mqttMessage) throws Exception { + /** + * 消费消息的回调接口,需要确保该接口不抛异常,该接口运行返回即代表消息消费成功。 + * 消费消息需要保证在规定时间内完成,如果消费耗时超过服务端约定的超时时间,对于可靠传输的模式,服务端可能会重试推送,业务需要做好幂等去重处理。超时时间约定参考限制 + * https://help.aliyun.com/document_detail/63620.html?spm=a2c4g.11186623.6.546.229f1f6ago55Fj + */ + + log.info("receive msg from topic {} , body is {}", s, new String(mqttMessage.getPayload())); + } + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + log.info("send msg succeed topic is : {}", iMqttDeliveryToken.getTopics()[0]); + } + }); + mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions()); + /** + * MQ4IoT支持点对点消息,点对点消息不需要经过订阅关系匹配。点对点消息的 topic 格式是 {{parentTopic}}/p2p/{{targetClientId}} + */ + final String p2pSendTopic = parentTopic + "/p2p/" + clientId; + MqttMessage mqttMessage = new MqttMessage(message); + mqttMessage.setQos(qosLevel); + mqttClient.publish(p2pSendTopic, mqttMessage); + } + + /** + * 支付方式 + */ + private String getPayTypeCode(String wayCodeType) { + if (CS.PAY_WAY_CODE_TYPE.WECHAT.equals(wayCodeType)) { + return "2003"; + }else if (CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(wayCodeType)) { + return "2001"; + }else if (CS.PAY_WAY_CODE_TYPE.YSFPAY.equals(wayCodeType)) { + return "2005"; + }else if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(wayCodeType)) { + return "7571"; + }else { + return "2000"; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/util/ConnectionOptionWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/util/ConnectionOptionWrapper.java new file mode 100644 index 0000000..29a86e3 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zgwlSpeaker/util/ConnectionOptionWrapper.java @@ -0,0 +1,125 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.zgwlSpeaker.util; + +import org.apache.commons.codec.binary.Base64; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.eclipse.paho.client.mqttv3.MqttConnectOptions.MQTT_VERSION_3_1_1; + +/** + * 工具类:负责封装 MQ4IOT 客户端的初始化参数设置 + */ +public class ConnectionOptionWrapper { + /** + * 内部连接参数 + */ + private MqttConnectOptions mqttConnectOptions; + /** + * MQ4IOT 实例 ID,购买后控制台获取 + */ + private String instanceId; + /** + * 账号 accesskey,从账号系统控制台获取 + */ + private String accessKey; + /** + * 账号 secretKey,从账号系统控制台获取,仅在Signature鉴权模式下需要设置 + */ + private String secretKey; + /** + * MQ4IOT clientId,由业务系统分配,需要保证每个 tcp 连接都不一样,保证全局唯一,如果不同的客户端对象(tcp 连接)使用了相同的 clientId 会导致连接异常断开。 + * clientId 由两部分组成,格式为 GroupID@@@DeviceId,其中 groupId 在 MQ4IOT 控制台申请,DeviceId 由业务方自己设置,clientId 总长度不得超过64个字符。 + */ + private String clientId; + /** + * 客户端使用的 Token 参数,仅在 Token 鉴权模式下需要设置,Key 为 token 类型,一个客户端最多存在三种类型,R,W,RW,Value 是 token内容。 + * 应用需要保证 token 在过期及时更新。否则会导致连接异常。 + */ + private Map tokenData = new ConcurrentHashMap(); + + /** + * Token 鉴权模式下构造方法 + * + * @param instanceId MQ4IOT 实例 ID,购买后控制台获取 + * @param accessKey 账号 accesskey,从账号系统控制台获取 + * @param clientId MQ4IOT clientId,由业务系统分配 + * @param tokenData 客户端使用的 Token 参数,仅在 Token 鉴权模式下需要设置 + */ + public ConnectionOptionWrapper(String instanceId, String accessKey, String clientId, + Map tokenData) { + this.instanceId = instanceId; + this.accessKey = accessKey; + this.clientId = clientId; + if (tokenData != null) { + this.tokenData.putAll(tokenData); + } + mqttConnectOptions = new MqttConnectOptions(); + mqttConnectOptions.setUserName("Token|" + accessKey + "|" + instanceId); + StringBuilder builder = new StringBuilder(); + for (Map.Entry entry : tokenData.entrySet()) { + builder.append(entry.getKey()).append("|").append(entry.getValue()).append("|"); + } + if (builder.length() > 0) { + builder.setLength(builder.length() - 1); + } + mqttConnectOptions.setPassword(builder.toString().toCharArray()); + mqttConnectOptions.setCleanSession(true); + mqttConnectOptions.setKeepAliveInterval(90); + mqttConnectOptions.setAutomaticReconnect(true); + mqttConnectOptions.setMqttVersion(MQTT_VERSION_3_1_1); + mqttConnectOptions.setConnectionTimeout(5000); + } + + /** + * Signature 鉴权模式下构造方法 + * + * @param instanceId MQ4IOT 实例 ID,购买后控制台获取 + * @param accessKey 账号 accesskey,从账号系统控制台获取 + * @param clientId MQ4IOT clientId,由业务系统分配 + * @param secretKey 账号 secretKey,从账号系统控制台获取 + */ + public ConnectionOptionWrapper(String instanceId, String accessKey, String secretKey, + String clientId) throws NoSuchAlgorithmException, InvalidKeyException { + this.instanceId = instanceId; + this.accessKey = accessKey; + this.secretKey = secretKey; + this.clientId = clientId; + mqttConnectOptions = new MqttConnectOptions(); + mqttConnectOptions.setUserName("Signature|" + accessKey + "|" + instanceId); + mqttConnectOptions.setPassword(macSignature(clientId, secretKey).toCharArray()); + mqttConnectOptions.setCleanSession(true); + mqttConnectOptions.setKeepAliveInterval(90); + mqttConnectOptions.setAutomaticReconnect(true); + mqttConnectOptions.setMqttVersion(MQTT_VERSION_3_1_1); + mqttConnectOptions.setConnectionTimeout(5000); + } + + public MqttConnectOptions getMqttConnectOptions() { + return mqttConnectOptions; + } + + /** + * @param text 要签名的文本 + * @param secretKey 阿里云MQ secretKey + * @return 加密后的字符串 + * @throws InvalidKeyException + * @throws NoSuchAlgorithmException + */ + public static String macSignature(String text, + String secretKey) throws InvalidKeyException, NoSuchAlgorithmException { + Charset charset = Charset.forName("UTF-8"); + String algorithm = "HmacSHA1"; + Mac mac = Mac.getInstance(algorithm); + mac.init(new SecretKeySpec(secretKey.getBytes(charset), algorithm)); + byte[] bytes = mac.doFinal(text.getBytes(charset)); + return new String(Base64.encodeBase64(bytes), charset); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zwSpeaker/ZwSpeakerService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zwSpeaker/ZwSpeakerService.java new file mode 100644 index 0000000..46d0db9 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/device/speaker/zwSpeaker/ZwSpeakerService.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.thirdparty.device.speaker.zwSpeaker; + +import cn.hutool.core.util.IdUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.device.ISpeakerService; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.model.device.ZwParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.thirdparty.service.zw.model.request.NotifyMsgRequest; +import com.jeequan.jeepay.thirdparty.service.zw.model.response.BaseResponse; +import com.jeequan.jeepay.thirdparty.service.zw.uils.SmartLinkUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/* + * 云喇叭厂商: 智网 + * + * @author xiaoyu + * + * @date 2023/4/11 14:39 + */ +@Slf4j +@Service +public class ZwSpeakerService implements ISpeakerService { + + @Override + public void send(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) throws BizException { + sendCustomMsg(deviceParams, payOrderInfo); + } + + @Override + public void sendCustomMsg(JSONObject deviceParams, PayOrderInfo4Device payOrderInfo) { + + ZwParams zwParams = getZwParams(deviceParams); + + NotifyMsgRequest request = new NotifyMsgRequest(); + request.setIndex(IdUtil.fastSimpleUUID()); + request.setSn(zwParams.getDeviceParams().getDeviceNo()); + request.setToken(zwParams.getProviderParams().getToken()); + + // 会员余额支付 + if (PayOrderInfo4Device.BOARD_TYPE_MEMBER.equals(payOrderInfo.getWayCodeType())) { + request.setMessage("会员余额支付" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + }if (PayOrderInfo4Device.BOARD_TYPE_CANCEL.equals(payOrderInfo.getWayCodeType())) { + request.setMessage("客户取消付款" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount()) + "元"); + }else if (StringUtils.isNotBlank(zwParams.getProviderParams().getCustomContent())){ + request.setMessage(zwParams.getProviderParams().getCustomContent() + AmountUtil.convertCent2DollarShort(payOrderInfo.getAmount()+"")+ "元"); + } + + BaseResponse response = SmartLinkUtil.soundNotifyMsg(request); + + if (!response.isSuccess()) { + throw new BizException(response.getRespMsg()); + } + } + + private ZwParams getZwParams(JSONObject deviceParams) { + JSONObject zwJSON = new JSONObject(); + zwJSON.put("providerParams", JSON.parseObject(deviceParams.getString("providerParams"))); + zwJSON.put("deviceParams", JSON.parseObject(deviceParams.getString("deviceParams"))); + + return JSON.parseObject(zwJSON.toJSONString(), ZwParams.class); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientEntry.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientEntry.java new file mode 100644 index 0000000..e71ea32 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientEntry.java @@ -0,0 +1,110 @@ +package com.jeequan.jeepay.thirdparty.model; + +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.AlipayRequest; +import com.alipay.api.AlipayResponse; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.ChannelException; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/*** +* 支付宝的 client 实际调用对象 +* +* @author terrfly +* @date 2022/11/10 9:32 +*/ +@Slf4j +@Data +@AllArgsConstructor +public class AlipayClientEntry { + + + //默认为 不使用证书方式 + private Byte useCert = CS.NO; + + /** 缓存支付宝client 对象 **/ + private AlipayClient alipayClient; + + /** 封装支付宝接口调用函数 **/ + public T execute(AlipayRequest request){ + + try { + + T alipayResp = null; + + if(useCert != null && useCert == CS.YES){ //证书加密方式 + alipayResp = alipayClient.certificateExecute(request); + + }else{ //key 或者 空都为默认普通加密方式 + alipayResp = alipayClient.execute(request); + } + + return alipayResp; + + } catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。 + + log.error("调起支付宝execute[AlipayApiException]异常!", e); + //如果数据返回出现验签异常,则需要抛出: UNKNOWN 异常。 + throw ChannelException.sysError(e.getMessage()); + + } catch (Exception e) { + log.error("调起支付宝execute[Exception]异常!", e); + throw ChannelException.sysError("调用支付宝client服务异常"); + } + } + + /** 封装支付宝接口调用函数 **/ + public T execute(AlipayRequest request, Byte isCert){ + + try { + + T alipayResp = null; + + if(isCert != null && isCert == CS.YES){ //证书加密方式 + alipayResp = alipayClient.certificateExecute(request); + + }else{ //key 或者 空都为默认普通加密方式 + alipayResp = alipayClient.execute(request); + } + + return alipayResp; + + } catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。 + + log.error("调起支付宝execute[AlipayApiException]异常!", e); + //如果数据返回出现验签异常,则需要抛出: UNKNOWN 异常。 + throw ChannelException.sysError(e.getMessage()); + + } catch (Exception e) { + log.error("调起支付宝execute[Exception]异常!", e); + throw ChannelException.sysError("调用支付宝client服务异常"); + } + } + + /** 封装支付宝接口调用函数 **/ + public T pageExecute(AlipayRequest request){ + + try { + + T alipayResp = null; + + alipayResp = alipayClient.pageExecute(request); + + return alipayResp; + + } catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。 + + log.error("调起支付宝execute[AlipayApiException]异常!", e); + //如果数据返回出现验签异常,则需要抛出: UNKNOWN 异常。 + throw ChannelException.sysError(e.getMessage()); + + } catch (Exception e) { + log.error("调起支付宝execute[Exception]异常!", e); + throw ChannelException.sysError("调用支付宝client服务异常"); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientWrapper.java new file mode 100644 index 0000000..c4737d4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/AlipayClientWrapper.java @@ -0,0 +1,191 @@ +package com.jeequan.jeepay.thirdparty.model; + +import com.alipay.api.*; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + + /* +* 支付宝Client 包装类 +* +* @author terrfly +* @date 2021/6/8 17:28 +*/ +@Slf4j +@Data +@AllArgsConstructor +public class AlipayClientWrapper { + + /** 缓存支付宝client对象 (支付使用) **/ + private AlipayClientEntry alipayClient; + + /** 缓存支付宝client对象 (服务窗获取userId) **/ + private AlipayClientEntry alipayClientByOauth2; + + /** 缓存支付宝client对象 (小程序获取userId ) **/ + private AlipayClientEntry alipayClientByOauth2Lite; + + + /* + * 构建支付宝client 包装类 + * + * @author terrfly + * @date 2021/6/8 17:46 + */ + public static AlipayClientEntry buildAlipayClientWrapper(Byte useCert, Byte sandbox, String appId, + String privateKey, String alipayPublicKey, String signType, + String appCert, String alipayPublicCert, String alipayRootCert){ + + //避免空值 + sandbox = sandbox == null ? CS.NO : sandbox; + + AlipayClient alipayClient = null; + if(useCert != null && useCert == CS.YES){ //证书的方式 + + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + certAlipayRequest.setServerUrl(sandbox == CS.YES ? com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.SANDBOX_SERVER_URL : com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.PROD_SERVER_URL); + certAlipayRequest.setAppId(appId); + certAlipayRequest.setPrivateKey(privateKey); + certAlipayRequest.setFormat(com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.FORMAT); + certAlipayRequest.setCharset(com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.CHARSET); + certAlipayRequest.setSignType(signType); + + certAlipayRequest.setCertPath(channelCertConfigKitBean.getCertFilePath(appCert)); + certAlipayRequest.setAlipayPublicCertPath(channelCertConfigKitBean.getCertFilePath(alipayPublicCert)); + certAlipayRequest.setRootCertPath(channelCertConfigKitBean.getCertFilePath(alipayRootCert)); + try { + alipayClient = new DefaultAlipayClient(certAlipayRequest); + } catch (AlipayApiException e) { + log.error("error" ,e); + alipayClient = null; + } + }else{ + alipayClient = new DefaultAlipayClient(sandbox == CS.YES ? com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.SANDBOX_SERVER_URL : com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.PROD_SERVER_URL + , appId, privateKey, com.jeequan.jeepay.core.model.params.alipay.AlipayConfig.FORMAT, AlipayConfig.CHARSET, + alipayPublicKey, signType); + } + + return new AlipayClientEntry(useCert, alipayClient); + } + + public static AlipayClientWrapper buildAlipayClientWrapper(AlipayIsvParams alipayParams, AlipayOauth2Params alipayOauth2Params){ + + AlipayClientEntry clientByPay = null; + AlipayClientEntry clientByOauth2 = null; + AlipayClientEntry clientByOauth2Lite = null; + + if(alipayParams != null){ + clientByPay = buildAlipayClientWrapper( + alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(), + alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(), + alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert() + ); + } + + if(alipayOauth2Params != null && StringUtils.isNotEmpty(alipayOauth2Params.getAppId())){ + clientByOauth2 = buildAlipayClientWrapper( + alipayOauth2Params.getUseCert(), alipayOauth2Params.getSandbox(), alipayOauth2Params.getAppId(), alipayOauth2Params.getPrivateKey(), + alipayOauth2Params.getAlipayPublicKey(), alipayOauth2Params.getSignType(), alipayOauth2Params.getAppPublicCert(), + alipayOauth2Params.getAlipayPublicCert(), alipayOauth2Params.getAlipayRootCert() + ); + } + + if(alipayOauth2Params != null && alipayOauth2Params.getLiteParams() != null && StringUtils.isNotEmpty(alipayOauth2Params.getLiteParams().getAppId())){ + clientByOauth2Lite = buildAlipayClientWrapper( + alipayOauth2Params.getLiteParams().getUseCert(), alipayOauth2Params.getLiteParams().getSandbox(), alipayOauth2Params.getLiteParams().getAppId(), alipayOauth2Params.getLiteParams().getPrivateKey(), + alipayOauth2Params.getLiteParams().getAlipayPublicKey(), alipayOauth2Params.getLiteParams().getSignType(), alipayOauth2Params.getLiteParams().getAppPublicCert(), + alipayOauth2Params.getLiteParams().getAlipayPublicCert(), alipayOauth2Params.getLiteParams().getAlipayRootCert() + ); + } + + return new AlipayClientWrapper(clientByPay, clientByOauth2, clientByOauth2Lite); + } + + public static AlipayClientWrapper buildAlipayClientWrapper(AlipayNormalMchParams alipayParams, AlipayOauth2Params alipayOauth2Params){ + + AlipayClientEntry clientByPay = null; + AlipayClientEntry clientByOauth2 = null; + AlipayClientEntry clientByOauth2Lite = null; + + if(alipayParams != null){ + clientByPay = buildAlipayClientWrapper( + alipayParams.getUseCert(), alipayParams.getSandbox(), alipayParams.getAppId(), alipayParams.getPrivateKey(), + alipayParams.getAlipayPublicKey(), alipayParams.getSignType(), alipayParams.getAppPublicCert(), + alipayParams.getAlipayPublicCert(), alipayParams.getAlipayRootCert() + ); + } + + if(alipayOauth2Params != null && StringUtils.isNotEmpty(alipayOauth2Params.getAppId())){ + clientByOauth2 = buildAlipayClientWrapper( + alipayOauth2Params.getUseCert(), alipayOauth2Params.getSandbox(), alipayOauth2Params.getAppId(), alipayOauth2Params.getPrivateKey(), + alipayOauth2Params.getAlipayPublicKey(), alipayOauth2Params.getSignType(), alipayOauth2Params.getAppPublicCert(), + alipayOauth2Params.getAlipayPublicCert(), alipayOauth2Params.getAlipayRootCert() + ); + } + + if(alipayOauth2Params != null && alipayOauth2Params.getLiteParams() != null && StringUtils.isNotEmpty(alipayOauth2Params.getLiteParams().getAppId())){ + clientByOauth2Lite = buildAlipayClientWrapper( + alipayOauth2Params.getLiteParams().getUseCert(), alipayOauth2Params.getLiteParams().getSandbox(), alipayOauth2Params.getLiteParams().getAppId(), alipayOauth2Params.getLiteParams().getPrivateKey(), + alipayOauth2Params.getLiteParams().getAlipayPublicKey(), alipayOauth2Params.getLiteParams().getSignType(), alipayOauth2Params.getLiteParams().getAppPublicCert(), + alipayOauth2Params.getLiteParams().getAlipayPublicCert(), alipayOauth2Params.getLiteParams().getAlipayRootCert() + ); + } + + return new AlipayClientWrapper(clientByPay, clientByOauth2, clientByOauth2Lite); + } + + + + /** 封装支付宝接口调用函数 --> 默认调用 pay的 **/ + public T execute(AlipayRequest request){ + + if(this.alipayClient == null){ + throw new BizException("获取支付宝client失败!"); + } + + return this.alipayClient.execute(request); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/IsvConfigBy3rdContext.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/IsvConfigBy3rdContext.java new file mode 100644 index 0000000..f006e40 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/IsvConfigBy3rdContext.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.thirdparty.model; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * Isv支付参数信息 放置到内存, 避免多次查询操作 + * + * @author terrfly + * @date 2021/6/8 17:28 + */ +@Data +public class IsvConfigBy3rdContext extends com.jeequan.jeepay.core.model.context.IsvConfigContext { + + /** 缓存支付宝client 对象 **/ + private AlipayClientWrapper alipayClientWrapper; + + /** 缓存直付通client 对象 **/ + private ZftpayClientWrapper zftpayClientWrapper; + + /** 缓存 wxServiceWrapper 对象 **/ + private WxServiceWrapper wxServiceWrapper; + + /** 缓存 缓存支付宝client 对象 ( 其他oauth2配置项 ) k-v: v1313_LIST_202201010101, AlipayClientWrapper **/ + private Map alipayClientWrapperByOauth2diyMap = new HashMap<>(); + + /** 缓存 wxServiceWrapper 对象( 其他oauth2配置项 ) **/ + private Map wxServiceWrapperByOauth2diyMap = new HashMap<>(); + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/MchAppConfigBy3rdContext.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/MchAppConfigBy3rdContext.java new file mode 100644 index 0000000..0f07b07 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/MchAppConfigBy3rdContext.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.thirdparty.model; + +import lombok.Data; + +/** + * 商户应用支付参数信息 + * 放置到内存, 避免多次查询操作 + * + * @author terrfly + * @date 2021/6/8 17:29 + */ +@Data +public class MchAppConfigBy3rdContext extends com.jeequan.jeepay.core.model.context.MchAppConfigContext { + + /** 缓存支付宝client 对象 **/ + private AlipayClientWrapper alipayClientWrapper; + + /** 缓存 wxServiceWrapper 对象 **/ + private WxServiceWrapper wxServiceWrapper; + + /** 缓存 Paypal 对象 **/ + private PaypalWrapper paypalWrapper; + + public AlipayClientWrapper getAlipayClientWrapper(){ + return isIsvsubMch() ? ((IsvConfigBy3rdContext)isvConfigContext).getAlipayClientWrapper(): alipayClientWrapper; + } + + public WxServiceWrapper getWxServiceWrapper(){ + return isIsvsubMch() ? ((IsvConfigBy3rdContext)isvConfigContext).getWxServiceWrapper(): wxServiceWrapper; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/PaypalWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/PaypalWrapper.java new file mode 100644 index 0000000..f62247c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/PaypalWrapper.java @@ -0,0 +1,209 @@ +package com.jeequan.jeepay.thirdparty.model; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.params.pppay.PpPayNormalMchParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.paypal.core.PayPalEnvironment; +import com.paypal.core.PayPalHttpClient; +import com.paypal.http.HttpResponse; +import com.paypal.http.serializer.Json; +import com.paypal.orders.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * none. + * + * @author 陈泉 + * @package com.jeequan.jeepay.pay.model + * @create 2021/11/15 19:10 + */ +@Slf4j +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PaypalWrapper { + private PayPalEnvironment environment; + private PayPalHttpClient client; + + private String notifyWebhook; + private String refundWebhook; + + public ChannelRetMsg processOrder(String token, PayOrder payOrder) throws IOException { + return processOrder(token, payOrder, false); + } + + public List processOrder(String order) { + return processOrder(order, "null"); + } + + // 解析拼接 ID + public List processOrder(String order, String afterOrderId) { + String ppOrderId = "null"; + String ppCatptId = "null"; + if (order != null) { + if (order.contains(",")) { + String[] split = order.split(","); + if (split.length == 2) { + ppCatptId = split[1]; + ppOrderId = split[0]; + } + } + } + if (afterOrderId != null && !"null".equalsIgnoreCase(afterOrderId)) { + ppOrderId = afterOrderId; + } + + if ("null".equalsIgnoreCase(ppCatptId)) { + ppCatptId = null; + } + if ("null".equalsIgnoreCase(ppOrderId)) { + ppOrderId = null; + } + + return Arrays.asList(ppOrderId, ppCatptId); + } + + /** + * 处理并捕获订单 + * 由于 Paypal 创建订单后需要进行一次 Capture(捕获) 才可以正确获取到订单的支付状态 + * + * @param token + * @param payOrder + * @param isCapture + * @return + * @throws IOException + */ + public ChannelRetMsg processOrder(String token, PayOrder payOrder, boolean isCapture) throws IOException { + // Paypal 创建订单存在一个 Token,当订单捕获之后会有一个 捕获的ID ,退款需要用到 + String ppOrderId = this.processOrder(payOrder.getChannelOrderNo(), token).get(0); + String ppCatptId = this.processOrder(payOrder.getChannelOrderNo()).get(1); + + ChannelRetMsg channelRetMsg = ChannelRetMsg.waiting(); + channelRetMsg.setResponseEntity(textResp("ERROR")); + + // 如果订单 ID 还不存在,等待 + if (ppOrderId == null) { + channelRetMsg.setChannelErrCode("201"); + channelRetMsg.setChannelErrMsg("捕获订单请求失败"); + return channelRetMsg; + } else { + Order order; + + channelRetMsg.setChannelOrderId(ppOrderId + "," + "null"); + + // 如果 捕获 ID 不存在 + if (ppCatptId == null && isCapture) { + OrderRequest orderRequest = new OrderRequest(); + OrdersCaptureRequest ordersCaptureRequest = new OrdersCaptureRequest(ppOrderId); + ordersCaptureRequest.requestBody(orderRequest); + + // 捕获订单 + HttpResponse response = this.getClient().execute(ordersCaptureRequest); + + if (response.statusCode() != 201) { + channelRetMsg.setChannelErrCode("201"); + channelRetMsg.setChannelErrMsg("捕获订单请求失败"); + return channelRetMsg; + } + order = response.result(); + } else { + OrdersGetRequest request = new OrdersGetRequest(ppOrderId); + HttpResponse response = this.getClient().execute(request); + + if (response.statusCode() != 200) { + channelRetMsg.setChannelOrderId(ppOrderId); + channelRetMsg.setChannelErrCode("200"); + channelRetMsg.setChannelErrMsg("请求订单详情失败"); + return channelRetMsg; + } + + order = response.result(); + } + + String status = order.status(); + String orderJsonStr = new Json().serialize(order); + JSONObject orderJson = JSONUtil.parseObj(orderJsonStr); + + for (PurchaseUnit purchaseUnit : order.purchaseUnits()) { + if (purchaseUnit.payments() != null) { + for (Capture capture : purchaseUnit.payments().captures()) { + ppCatptId = capture.id(); + break; + } + } + } + + String orderUserId = orderJson.getByPath("payer.payer_id", String.class); + + ChannelRetMsg result = new ChannelRetMsg(); + result.setNeedQuery(true); + result.setChannelOrderId(ppOrderId + "," + ppCatptId); // 渠道订单号 + result.setChannelUserId(orderUserId); // 支付用户ID + result.setChannelAttach(orderJsonStr); // Capture 响应数据 + result.setResponseEntity(textResp("SUCCESS")); // 响应数据 + result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中 + result = dispatchCode(status, result); // 处理状态码 + return result; + } + } + + /** + * 处理 Paypal 状态码 + * + * @param status 状态码 + * @param channelRetMsg 通知信息 + * @return 通知信息 + */ + public ChannelRetMsg dispatchCode(String status, ChannelRetMsg channelRetMsg) { + if ("SAVED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } else if ("APPROVED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } else if ("VOIDED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL); + } else if ("COMPLETED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS); + } else if ("PAYER_ACTION_REQUIRED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } else if ("CREATED".equalsIgnoreCase(status)) { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING); + } else { + channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.UNKNOWN); + } + return channelRetMsg; + } + + public ResponseEntity textResp(String text) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.TEXT_HTML); + return new ResponseEntity(text, httpHeaders, HttpStatus.OK); + } + + public static PaypalWrapper buildPaypalWrapper(PpPayNormalMchParams ppPayNormalMchParams){ + PaypalWrapper paypalWrapper = new PaypalWrapper(); + PayPalEnvironment environment = new PayPalEnvironment.Live(ppPayNormalMchParams.getClientId(), ppPayNormalMchParams.getSecret()); + if (ppPayNormalMchParams.getSandbox() == 1) { + environment = new PayPalEnvironment.Sandbox(ppPayNormalMchParams.getClientId(), ppPayNormalMchParams.getSecret()); + } + paypalWrapper.setEnvironment(environment); + paypalWrapper.setClient(new PayPalHttpClient(environment)); + paypalWrapper.setNotifyWebhook(ppPayNormalMchParams.getNotifyWebhook()); + paypalWrapper.setRefundWebhook(ppPayNormalMchParams.getRefundWebhook()); + return paypalWrapper; + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxServiceWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxServiceWrapper.java new file mode 100644 index 0000000..33fb0da --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxServiceWrapper.java @@ -0,0 +1,133 @@ +package com.jeequan.jeepay.thirdparty.model; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AllArgsConstructor; +import lombok.Data; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; +import org.apache.commons.lang3.StringUtils; + +/** + * wxService 包装类 + * + * @author terrfly + * @date 2021/6/8 17:30 + */ +@Data +@AllArgsConstructor +public class WxServiceWrapper { + + /** 缓存微信API版本 **/ + private String apiVersion; + + /** 缓存 wxPayService 对象 **/ + private WxPayService wxPayService; + + /** 缓存 wxJavaService 对象 **/ + private WxMpService wxMpService; + + /** 缓存 wxJavaService 小程序 对象 **/ + private WxMaService wxMaService; + + + public static WxServiceWrapper buildWxServiceWrapper(String mchId, String appId, String mchKey, String apiVersion, String apiV3Key, + String serialNo, String cert, String apiClientCert, String apiClientKey, WxpayOauth2Params wxpayOauth2Params){ + + WxPayConfig wxPayConfig = new WxPayConfig(); + wxPayConfig.setMchId(mchId); + wxPayConfig.setAppId(appId); + wxPayConfig.setMchKey(mchKey); + + if (CS.PAY_IF_VERSION.WX_V2.equals(apiVersion)) { // 微信API V2 + wxPayConfig.setSignType(WxPayConstants.SignType.MD5); + } + + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + + if(StringUtils.isNotBlank(apiV3Key)) { + wxPayConfig.setApiV3Key(apiV3Key); + } + if(StringUtils.isNotBlank(serialNo)) { + wxPayConfig.setCertSerialNo(serialNo); + } + if(StringUtils.isNotBlank(cert)){ + wxPayConfig.setKeyPath(channelCertConfigKitBean.getCertFilePath(cert)); + } + if(StringUtils.isNotBlank(apiClientCert)){ + wxPayConfig.setPrivateCertPath(channelCertConfigKitBean.getCertFilePath(apiClientCert)); + } + if(StringUtils.isNotBlank(apiClientKey)) { + wxPayConfig.setPrivateKeyPath(channelCertConfigKitBean.getCertFilePath(apiClientKey)); + } + + WxPayService wxPayService = new WxPayServiceImpl(); + wxPayService.setConfig(wxPayConfig); //微信配置信息 + + return new WxServiceWrapper(apiVersion, wxPayService, null, null).putOauthInfo(wxpayOauth2Params); + } + + private WxServiceWrapper putOauthInfo(WxpayOauth2Params wxpayOauth2Params){ + + if(wxpayOauth2Params != null){ + // 当 公众号的配置不为空时设置 wxMpService + if(StringUtils.isNotEmpty(wxpayOauth2Params.getAppId()) && StringUtils.isNotEmpty(wxpayOauth2Params.getAppSecret())){ + WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl(); + wxMpConfigStorage.setAppId(wxpayOauth2Params.getAppId()); + wxMpConfigStorage.setSecret(wxpayOauth2Params.getAppSecret()); + this.wxMpService = new WxMpServiceImpl(); + this.wxMpService.setWxMpConfigStorage(wxMpConfigStorage); //微信配置信息 + } + + // 当小程序的配置不为空时设置 wxMaService + if(StringUtils.isNotEmpty(wxpayOauth2Params.getLiteAppId()) && StringUtils.isNotEmpty(wxpayOauth2Params.getLiteAppSecret())){ + WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl(); + config.setAppid(wxpayOauth2Params.getLiteAppId()); + config.setSecret(wxpayOauth2Params.getLiteAppSecret()); + this.wxMaService = new WxMaServiceImpl(); + this.wxMaService.setWxMaConfig(config); + } + } + return this; + } + + + public static WxServiceWrapper buildWxServiceWrapper(WxpayIsvParams wxpayParams, WxpayOauth2Params wxpayOauth2Params){ + + if(wxpayParams != null){ + return buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(), + wxpayParams.getKey(), wxpayParams.getApiVersion(), wxpayParams.getApiV3Key(), + wxpayParams.getSerialNo(), wxpayParams.getCert(), wxpayParams.getApiClientCert(), wxpayParams.getApiClientKey(), + wxpayOauth2Params); + } + + return new WxServiceWrapper(null, null, null, null).putOauthInfo(wxpayOauth2Params); + + + } + + public static WxServiceWrapper buildWxServiceWrapper(WxpayNormalMchParams wxpayParams, WxpayOauth2Params wxpayOauth2Params){ + + if(wxpayParams != null){ + return buildWxServiceWrapper(wxpayParams.getMchId(), wxpayParams.getAppId(), + wxpayParams.getKey(), wxpayParams.getApiVersion(), wxpayParams.getApiV3Key(), + wxpayParams.getSerialNo(), wxpayParams.getCert(), wxpayParams.getApiClientCert(), wxpayParams.getApiClientKey(), + wxpayOauth2Params); + } + + return new WxServiceWrapper(null, null, null, null).putOauthInfo(wxpayOauth2Params); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxmpServerContext.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxmpServerContext.java new file mode 100644 index 0000000..335e39f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/WxmpServerContext.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.thirdparty.model; + +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.DBWxMpConfig; +import com.jeequan.jeepay.service.impl.SysConfigService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +/** +* 获取 WxMpService +* +* @author zx +* @site https://www.jeepay.vip +* @date 2021/10/15 9:37 +*/ +@Slf4j +@Component +public class WxmpServerContext { + + private static WxMpService wxMpService = null; + + public WxMpService getWxService(DBWxMpConfig wxMpConfig){ + + if (!SysConfigService.IS_USE_CACHE) { + return getWxMpService(wxMpConfig); + } + + if(wxMpService == null){ + this.init(wxMpConfig); + } + + return wxMpService; + } + + public void clearWxService(){ + if (!SysConfigService.IS_USE_CACHE) { + return; + } + + wxMpService = null; + log.info("微信公众号wxMpService对象已重置"); + } + + private synchronized void init(DBWxMpConfig wxMpConfig){ + + wxMpService = getWxMpService(wxMpConfig); + log.info("微信公众号wxMpService对象初始化完成"); + } + + private WxMpService getWxMpService(DBWxMpConfig wxMpConfig) { + if(wxMpConfig == null || StringUtils.isAnyBlank(wxMpConfig.getWxAppId(), wxMpConfig.getWxAppSecret())){ + return null; + } + + // 微信java使用redis缓存 + RedisTemplateWxRedisOps wxRedisOps = new RedisTemplateWxRedisOps(RedisUtil.getStringRedisTemplate()); + + WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(wxRedisOps, CS.CACHE_KEY_WX_JAVA); + config.setAppId(wxMpConfig.getWxAppId()); // 设置微信公众号的appid + config.setSecret(wxMpConfig.getWxAppSecret()); // 设置微信公众号的app corpSecret + + WxMpService wxService = new WxMpServiceImpl(); + wxService.setWxMpConfigStorage(config); + + return wxService; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/ZftpayClientWrapper.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/ZftpayClientWrapper.java new file mode 100644 index 0000000..09dfc3d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/model/ZftpayClientWrapper.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.thirdparty.model; + +import com.alipay.api.*; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + + /** + * 支付宝Client 包装类 + * + * @author terrfly + * @date 2021/6/8 17:28 + */ + @Slf4j + @Data + @AllArgsConstructor + public class ZftpayClientWrapper { + + + //默认为 不使用证书方式 + private Byte useCert = CS.NO; + + /** 缓存支付宝client 对象 **/ + private AlipayClient alipayClient; + + /** 封装支付宝接口调用函数 **/ + public T execute(AlipayRequest request){ + + try { + + T alipayResp = null; + + if(useCert != null && useCert == CS.YES){ //证书加密方式 + alipayResp = alipayClient.certificateExecute(request); + + }else{ //key 或者 空都为默认普通加密方式 + alipayResp = alipayClient.execute(request); + } + + return alipayResp; + + } catch (AlipayApiException e) { // 调起接口前出现异常,如私钥问题。 调起后出现验签异常等。 + + log.error("调起支付宝execute[AlipayApiException]异常!", e); + //如果数据返回出现验签异常,则需要抛出: UNKNOWN 异常。 + throw ChannelException.sysError(e.getMessage()); + + } catch (Exception e) { + log.error("调起支付宝execute[Exception]异常!", e); + throw ChannelException.sysError("调用支付宝client服务异常"); + } + } + + + + /** + * 构建支付宝client 包装类 + * + * @author terrfly + * @date 2021/6/8 17:46 + */ + public static ZftpayClientWrapper buildZftpayClientWrapper(Byte useCert, Byte sandbox, String appId, String privateKey, String alipayPublicKey, String signType, String appCert, + String alipayPublicCert, String alipayRootCert){ + + //避免空值 + sandbox = sandbox == null ? CS.NO : sandbox; + + AlipayClient alipayClient = null; + if(useCert != null && useCert == CS.YES){ //证书的方式 + + ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class); + + CertAlipayRequest certAlipayRequest = new CertAlipayRequest(); + certAlipayRequest.setServerUrl(sandbox == CS.YES ? AlipayConfig.SANDBOX_SERVER_URL : AlipayConfig.PROD_SERVER_URL); + certAlipayRequest.setAppId(appId); + certAlipayRequest.setPrivateKey(privateKey); + certAlipayRequest.setFormat(AlipayConfig.FORMAT); + certAlipayRequest.setCharset(AlipayConfig.CHARSET); + certAlipayRequest.setSignType(signType); + + certAlipayRequest.setCertPath(channelCertConfigKitBean.getCertFilePath(appCert)); + certAlipayRequest.setAlipayPublicCertPath(channelCertConfigKitBean.getCertFilePath(alipayPublicCert)); + certAlipayRequest.setRootCertPath(channelCertConfigKitBean.getCertFilePath(alipayRootCert)); + try { + alipayClient = new DefaultAlipayClient(certAlipayRequest); + } catch (AlipayApiException e) { + log.error("error" ,e); + alipayClient = null; + } + }else{ + alipayClient = new DefaultAlipayClient(sandbox == CS.YES ? AlipayConfig.SANDBOX_SERVER_URL : AlipayConfig.PROD_SERVER_URL + , appId, privateKey, AlipayConfig.FORMAT, AlipayConfig.CHARSET, + alipayPublicKey, signType); + } + + return new ZftpayClientWrapper(useCert, alipayClient); + } + + + + public static ZftpayClientWrapper buildZftpayClientWrapper(ZftpayIsvParams zftpayParams){ + + return buildZftpayClientWrapper( + zftpayParams.getUseCert(), zftpayParams.getSandbox(), zftpayParams.getAppId(), zftpayParams.getPrivateKey(), + zftpayParams.getAlipayPublicKey(), zftpayParams.getSignType(), zftpayParams.getAppPublicCert(), + zftpayParams.getAlipayPublicCert(), zftpayParams.getAlipayRootCert() + ); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/AlipayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/AlipayChannelUserService.java new file mode 100644 index 0000000..3e0ca11 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/AlipayChannelUserService.java @@ -0,0 +1,131 @@ +package com.jeequan.jeepay.thirdparty.oauth2; + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.request.AlipaySystemOauthTokenRequest; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.exception.ChannelException; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.model.AlipayClientEntry; +import com.jeequan.jeepay.thirdparty.model.AlipayClientWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 支付宝: 获取用户ID实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:21 +*/ +@Service +@Slf4j +public class AlipayChannelUserService implements IChannelUserService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String getIfCode() { + return CS.IF_CODE.ALIPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + String oauthUrl = AlipayConfig.PROD_OAUTH_URL; + String appId = null; + + if(mchAppConfigContext.isIsvsubMch()){ + + // 查询商户 配置 的oauth2配置 ( 支付参数配置 ) selectOauth2InfoId: 配置的oauth2参数 + String ifCode = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, QRCodeParams.PAGE_TYPE_ALIPAY_H5); + String selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCode); + + AlipayOauth2Params isvParams = (AlipayOauth2Params) configContextQueryService + .queryIsvOauth2ParamsByAutoSelectOauth2InfoId(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode(), selectOauth2InfoId); + if(isvParams == null) { + throw new BizException("服务商支付宝oauth2参数没有配置!"); + } + appId = isvParams.getAppId(); + if(isvParams.getSandbox() != null && isvParams.getSandbox() == CS.YES){ + oauthUrl = AlipayConfig.SANDBOX_OAUTH_URL; + } + }else{ + //获取商户配置信息 + AlipayOauth2Params normalMchParams = (AlipayOauth2Params) configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode()); + if(normalMchParams == null) { + throw new BizException("商户应用支付宝oauth2参数没有配置!"); + } + appId = normalMchParams.getAppId(); + if(normalMchParams.getSandbox() != null && normalMchParams.getSandbox() == CS.YES){ + oauthUrl = AlipayConfig.SANDBOX_OAUTH_URL; + } + } + String alipayUserRedirectUrl = String.format(oauthUrl, appId, callbackUrlEncode); + log.info("alipayUserRedirectUrl={}", alipayUserRedirectUrl); + return ChannelUserInfoMsg.gen(alipayUserRedirectUrl, appId); // 支付宝不区分appId, alipayUserId 全局通用。 但是也需要区分沙箱和正式, 需要设置appID + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + + Byte isUseSubmchAccount = reqParams.getByte("isUseSubmchAccount"); + if(isUseSubmchAccount == null){ + isUseSubmchAccount = CS.NO; // 默认使用 服务商账号 + } + + AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest(); + request.setCode(reqParams.getString("auth_code")); request.setGrantType("authorization_code"); + +// ifCode = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, pageType); + AlipayClientWrapper alipayClientWrapper = configContextQueryService.getAlipayClientWrapperByAutoOauth2(mchAppConfigContext, getIfCode()); + + try { + + + // 获取商户自己的小程序 openId + if(QRCodeParams.PAGE_TYPE_ALIPAY_LITE.equals(pageType) && isUseSubmchAccount == CS.YES){ + return getOpenIdByIsvSubmchAccount(request, mchAppConfigContext); + } + + + // 小程序 && 服务商小程序配置不为空 + if(QRCodeParams.PAGE_TYPE_ALIPAY_LITE.equals(pageType) && alipayClientWrapper.getAlipayClientByOauth2Lite() != null){ + return alipayClientWrapper.getAlipayClientByOauth2Lite().execute(request).getUserId(); + } + + // 默认方式 + return alipayClientWrapper.getAlipayClientByOauth2().execute(request).getUserId(); + } catch (ChannelException e) { + e.printStackTrace(); + return null; + } + } + + /** 获取商户自己的小程序 openId **/ + private String getOpenIdByIsvSubmchAccount(AlipaySystemOauthTokenRequest req, MchAppConfigContext mchAppConfigContext) { + + AlipayOauth2Params alipayOauth2ParamsByMch = (AlipayOauth2Params) configContextQueryService.queryNormalOauth2Params + (mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY); + + // 小程序的配置信息 + AlipayOauth2Params alipayOauth2Params = alipayOauth2ParamsByMch.getLiteParams(); + + AlipayClientEntry clientByOauth2 = AlipayClientWrapper.buildAlipayClientWrapper( + alipayOauth2Params.getUseCert(), alipayOauth2Params.getSandbox(), alipayOauth2Params.getAppId(), alipayOauth2Params.getPrivateKey(), + alipayOauth2Params.getAlipayPublicKey(), alipayOauth2Params.getSignType(), alipayOauth2Params.getAppPublicCert(), + alipayOauth2Params.getAlipayPublicCert(), alipayOauth2Params.getAlipayRootCert() + ); + + return clientByOauth2.execute(req).getUserId(); + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxDepositService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxDepositService.java new file mode 100644 index 0000000..4ba796d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxDepositService.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.thirdparty.oauth2; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.icbc.api.internal.apache.http.impl.cookie.S; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * TODO + * 微信托管业务处理 + * @author crystal + * @date 2023/11/13 15:47 + */ +@Service +public class WxDepositService { + + public final static String DOMAIN = "https://xcx.shouyinbei.cn"; + + public final static String API_PREFIX = "/prod-mini-api"; + + public final static String THIRD_ACCESS_TOEN = "authAccessToken"; + + public final static String THIRD_COMPONENT_TOKEN = "componentToken"; + + /** + * 微信第三方渠道号appid + */ + public static final String THIRD_WX_APPID = "wx2aac7e9da59d74b0"; + + public static final String THIRD_USER_OPENID = "https://api.weixin.qq.com/sns/component/jscode2session?appid=APPID&js_code=CODE&grant_type=authorization_code&component_appid=COMPONENT_APPID&component_access_token=COMPONENT_ACCESS_TOKEN"; + /** + * 渠道授权获取openid地址 + */ + public static final String THIRD_OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/component/access_token?appid=APPID&code=CODE&grant_type=authorization_code&component_appid=COMPONENT_APPID&component_access_token=COMPONENT_ACCESS_TOKEN"; + + + public String getWxAccessToken(String appid,String tokenName) { + String url = DOMAIN + API_PREFIX + "/api/open/cache/get?appid="+appid; + String response = HttpUtil.get(url); + JSONObject result = JSON.parseObject(response); + JSONObject data = result.getJSONObject("data"); + return data.getString(tokenName); + } + + /** + * 获取第三方代开小程序 ACCESS_TOKEN + * @param appid + * @return + */ + public String getThirdAccessToken(String appid) { + return getWxAccessToken(appid,THIRD_ACCESS_TOEN); + } + + public String getComponentToken(String appid) { + return getWxAccessToken(appid,THIRD_COMPONENT_TOKEN); + } + + public String getThidOpenUserId(String appid,String code) { + String componentToken = getComponentToken(appid); + String url = THIRD_USER_OPENID.replace("COMPONENT_APPID",THIRD_WX_APPID).replace("CODE",code).replace("APPID",appid).replace("COMPONENT_ACCESS_TOKEN",componentToken); + String response = HttpUtil.get(url); + JSONObject result = JSON.parseObject(response); + return result.getString("openid"); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxpayChannelUserService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxpayChannelUserService.java new file mode 100644 index 0000000..66c6b6e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/oauth2/WxpayChannelUserService.java @@ -0,0 +1,152 @@ +package com.jeequan.jeepay.thirdparty.oauth2; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IChannelUserService; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelUserInfoMsg; +import com.jeequan.jeepay.thirdparty.model.WxServiceWrapper; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import com.jeequan.jeepay.thirdparty.util.WxLiteCodeUtils; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* +* 微信支付 获取微信openID实现类 +* +* @author terrfly +* +* @date 2021/6/8 17:22 +*/ +@Service +@Slf4j +public class WxpayChannelUserService implements IChannelUserService { + + @Autowired private ConfigContextQueryService configContextQueryService; + + /** 默认官方跳转地址 **/ + private static final String DEFAULT_OAUTH_URL = "https://open.weixin.qq.com/connect/oauth2/authorize"; + + @Override + public String getIfCode() { + return CS.IF_CODE.WXPAY; + } + + @Override + public ChannelUserInfoMsg buildUserRedirectUrl(String callbackUrlEncode, MchAppConfigContext mchAppConfigContext) { + + String appId = null; + String oauth2Url = ""; + + + // 特约商户 + if(mchAppConfigContext.isIsvsubMch()){ + + // 查询商户 配置 的oauth2配置 ( 支付参数配置 ) selectOauth2InfoId: 配置的oauth2参数 + String ifCode = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, QRCodeParams.PAGE_TYPE_WECHAT_H5); + String selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCode); + + + WxpayOauth2Params isvParams = (WxpayOauth2Params) configContextQueryService. + queryIsvOauth2ParamsByAutoSelectOauth2InfoId(mchAppConfigContext.getMchApplyment().getIsvNo(), getIfCode(), selectOauth2InfoId); + + if(isvParams == null) { + throw new BizException("服务商微信oauth2参数没有配置!"); + } + + appId = isvParams.getAppId(); + oauth2Url = isvParams.getOauth2Url(); + }else{ + //获取商户配置信息 + WxpayOauth2Params normalMchParams = (WxpayOauth2Params)configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + if(normalMchParams == null) { + throw new BizException("商户微信支付接口没有配置!"); + } + appId = normalMchParams.getAppId(); + oauth2Url = normalMchParams.getOauth2Url(); + } + + if(StringUtils.isBlank(oauth2Url)){ + oauth2Url = DEFAULT_OAUTH_URL; + } + String wxUserRedirectUrl = String.format(oauth2Url + "?appid=%s&scope=snsapi_base&state=&redirect_uri=%s&response_type=code#wechat_redirect", appId, callbackUrlEncode); + log.info("wxUserRedirectUrl={}", wxUserRedirectUrl); + return ChannelUserInfoMsg.gen(wxUserRedirectUrl, appId); + } + + @Override + public String getChannelUserId(String pageType, JSONObject reqParams, MchAppConfigContext mchAppConfigContext, String ifCode) { + String code = reqParams.getString("code"); + + Byte isUseSubmchAccount = reqParams.getByte("isUseSubmchAccount"); + if(isUseSubmchAccount == null){ + isUseSubmchAccount = CS.NO; // 默认使用 服务商账号 + } + + try { + +// ifCode = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, pageType); + WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapperByAutoOauth2(mchAppConfigContext, ifCode); + + // 小程序 + if(QRCodeParams.PAGE_TYPE_WECHAT_LITE.equals(pageType)){ + + // 获取商户自己的小程序 openId + if(isUseSubmchAccount == CS.YES){ + return getOpenIdByIsvSubmchAccount(code, mchAppConfigContext); + } + + // 使用新的调用方式 + return WxLiteCodeUtils.code2OpenId(wxServiceWrapper.getWxMaService(), code).getOpenid(); + + /*WxMaJscode2SessionResult sessionInfo = wxServiceWrapper.getWxMaService().getUserService().getSessionInfo(code); + + JSONObject result = new JSONObject(); + result.put("openid", sessionInfo.getOpenid()); + result.put("unionid", sessionInfo.getUnionid()); + return result.toJSONString();*/ + + }else{ // 公众号 + + return wxServiceWrapper.getWxMpService().getOAuth2Service().getAccessToken(code).getOpenId(); + + /*WxOAuth2AccessToken accessToken = wxServiceWrapper.getWxMpService().getOAuth2Service().getAccessToken(code); + + JSONObject result = new JSONObject(); + result.put("openid", accessToken.getOpenId()); + result.put("unionid", accessToken.getUnionId()); + return result.toJSONString();*/ + } + + } catch (WxErrorException e) { + log.error("微信公众号获取openID异常", e); + return null; + } + } + + + /** 获取商户自己的小程序 openId **/ + private String getOpenIdByIsvSubmchAccount(String code, MchAppConfigContext mchAppConfigContext) throws WxErrorException { + + WxpayOauth2Params oauth2Params = (WxpayOauth2Params) configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + + WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl(); + config.setAppid(oauth2Params.getLiteAppId()); + config.setSecret(oauth2Params.getLiteAppSecret()); + WxMaService wxMaService = new WxMaServiceImpl(); + wxMaService.setWxMaConfig(config); + + // 使用新的调用方式 + return WxLiteCodeUtils.code2OpenId(wxMaService, code).getOpenid(); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/BizOrderQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/BizOrderQueryService.java new file mode 100644 index 0000000..60f2015 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/BizOrderQueryService.java @@ -0,0 +1,58 @@ +package com.jeequan.jeepay.thirdparty.service; + +import cn.hutool.core.bean.BeanUtil; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.PayOrderDivisionRefundRecord; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.interfaces.IBizOrderQueryService; +import com.jeequan.jeepay.db.entity.PayOrderDivisionRecord; +import com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService; +import com.jeequan.jeepay.service.impl.PayOrderDivisionRefundRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +@Slf4j +@Service +public class BizOrderQueryService implements IBizOrderQueryService { + + @Autowired private PayOrderDivisionRecordService payOrderDivisionRecordService; + @Autowired private PayOrderDivisionRefundRecordService payOrderDivisionRefundRecordService; + + + @Override + public List queryPayOrderRefundDivisionRefundRecordList(RefundOrder refundOrder, PayOrder payOrder) { + + List result = new ArrayList<>(); + + + // 查询订单是否包含分账成功的账号 + List recordList = payOrderDivisionRecordService.list(PayOrderDivisionRecord.gw() + .eq(PayOrderDivisionRecord::getPayOrderId, refundOrder.getPayOrderId()) + .eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_SUCCESS) + ); + + // 不包含分账订单 + if(recordList.isEmpty()){ + return result; + } + + // 遍历分账记录 + for (PayOrderDivisionRecord record : recordList) { + + com.jeequan.jeepay.db.entity.RefundOrder refundOrderByDB = new com.jeequan.jeepay.db.entity.RefundOrder(); + BeanUtil.copyProperties(refundOrder, refundOrderByDB); + + com.jeequan.jeepay.db.entity.PayOrder payOrderByDB = new com.jeequan.jeepay.db.entity.PayOrder(); + BeanUtil.copyProperties(payOrder, payOrderByDB); + + result.add(payOrderDivisionRefundRecordService.genRecord(record, refundOrderByDB, payOrderByDB)); + } + + return result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextQueryService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextQueryService.java new file mode 100644 index 0000000..4585189 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextQueryService.java @@ -0,0 +1,591 @@ +package com.jeequan.jeepay.thirdparty.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApp; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.oauth2.Oauth2Params; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams; +import com.jeequan.jeepay.core.model.params.pppay.PpPayNormalMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.thirdparty.model.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/* + * 配置信息查询服务 (兼容 缓存 和 直接查询方式) + * + * @author terrfly + * + * @date 2021/11/18 14:41 + */ +@Slf4j +@Service +public class ConfigContextQueryService implements IConfigContextQueryService { + + @Autowired + ConfigContextService configContextService; + @Autowired + private MchInfoService mchInfoService; + @Autowired + private MchAppService mchAppService; + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private MchPayInterfaceConfigService mchPayInterfaceConfigService; + @Autowired + private MchPayPassageService mchPayPassageService; + @Autowired + private MchApplymentService mchApplymentService; + @Autowired + private MchInfoConverter mchInfoConverter; + @Autowired + private MchStoreService mchStoreService; + @Autowired + private TransferInterfaceConfigService transferInterfaceConfigService; + + private boolean isCache() { + return SysConfigService.IS_USE_CACHE; + } + + @Override + public MchApp queryMchApp(String mchNo, String mchAppId) { + + if (isCache()) { + return configContextService.getMchAppConfigContext(mchNo, mchAppId).getMchApp(); + } + + return mchInfoConverter.toModel(mchAppService.getOneByMch(mchNo, mchAppId)); + } + + @Override + public MchAppConfigContext queryMchInfoAndAppInfo(String mchAppId) { + return queryMchInfoAndAppInfo(mchAppService.getById(mchAppId).getMchNo(), mchAppId); + } + + @Override + public MchAppConfigContext queryMchInfoAndAppInfo(String mchNo, String mchAppId) { + + if (isCache()) { + return configContextService.getMchAppConfigContext(mchNo, mchAppId); + } + + MchInfo mchInfo = mchInfoService.getById(mchNo); + MchApp mchApp = queryMchApp(mchNo, mchAppId); + + if (mchInfo == null || mchApp == null) { + return null; + } + + MchAppConfigContext result = new MchAppConfigContext(); + result.setMchInfo(mchInfo); + result.setMchNo(mchNo); + result.setMchType(mchInfo.getType()); + + result.setMchApp(mchApp); + result.setAppId(mchAppId); + + return result; + } + + @Override + public NormalMchParams queryNormalMchParams(String mchNo, String mchAppId, String ifCode) { + + if (isCache()) { + return configContextService.getMchAppConfigContext(mchNo, mchAppId).getNormalMchParamsByIfCode(ifCode); + } + + // 查询商户的所有支持的参数配置 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.lambdaQuery() + .select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams) + .eq(PayInterfaceConfig::getState, CS.YES) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .eq(PayInterfaceConfig::getInfoId, mchAppId) + .eq(PayInterfaceConfig::getIfCode, ifCode) + .one(); + + if (payInterfaceConfig == null) { + return null; + } + + return NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()); + } + + + @Override + public IsvsubMchParams queryIsvsubMchParams(String mchNo, String mchAppId, String ifCode) { + + if (isCache()) { + return configContextService.getMchAppConfigContext(mchNo, mchAppId).getIsvsubMchParamsByIfCode(ifCode); + } + + // 查询商户的所有支持的参数配置 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getOne(PayInterfaceConfig.gw() + .select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams) + .eq(PayInterfaceConfig::getState, CS.YES) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .eq(PayInterfaceConfig::getInfoId, mchAppId) + .eq(PayInterfaceConfig::getIfCode, ifCode) + ); + + if (payInterfaceConfig == null) { + return null; + } + + return IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()); + } + + /** + * 商户号 + * + * @param mchExtNo + * @return + */ + @Override + public IsvsubMchParams queryNewIsvsubMchParams(String mchExtNo) { + MchApplyment merchant = mchApplymentService.getById(mchExtNo); + if (merchant == null) { + return null; + } + return IsvsubMchParams.factory(merchant.getIfCode(), merchant.getSuccResParameter()); + } + + + @Override + public IsvParams queryIsvParams(String isvNo, String ifCode) { + + if (isCache()) { + IsvConfigBy3rdContext isvConfigContext = configContextService.getIsvConfigContext(isvNo); + return isvConfigContext == null ? null : isvConfigContext.getIsvParams(ifCode); + } + + // 查询商户的所有支持的参数配置 + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.lambdaQuery() + .select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams, PayInterfaceConfig::getAltId) + .eq(PayInterfaceConfig::getState, CS.YES) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(PayInterfaceConfig::getInfoId, isvNo) + .eq(PayInterfaceConfig::getIfCode, ifCode) + .one(); + + if (payInterfaceConfig == null) { + return null; + } + + IsvParams isvParams = IsvParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()); + isvParams.setAltId(payInterfaceConfig.getAltId()); + return isvParams; + } + + @Override + public IsvParams queryTransferIsvParams(TransferSubject transferSubject) { + return queryTransferIsvParams(transferSubject.getIsvNo(), transferSubject.getTransIfCode()); + } + + @Override + public IsvParams queryTransferIsvParams(String isvNo, String transIfCode) { + + if (isCache()) { + IsvConfigBy3rdContext isvConfigContext = configContextService.getIsvConfigContext(isvNo); + return isvConfigContext == null ? null : isvConfigContext.getIsvParams(transIfCode); + } + + // 查询商户的所有支持的参数配置 + TransferInterfaceConfigEntity interfaceConfig = transferInterfaceConfigService.lambdaQuery() + .eq(TransferInterfaceConfigEntity::getState, CS.YES) + .eq(TransferInterfaceConfigEntity::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(TransferInterfaceConfigEntity::getInfoId, isvNo) + .eq(TransferInterfaceConfigEntity::getTransIfCode, transIfCode) + .one(); + + if (interfaceConfig == null) { + return null; + } + + return IsvParams.factory(interfaceConfig.getTransIfCode(), interfaceConfig.getTransIfParams()); + } + + /** + * 商户进件后,通过该方法获取渠道参数 + * + * @return + */ + @Override + public IsvParams queryIsvParams(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment) { + return queryIsvParams(mchApplyment.getIsvNo(), mchApplyment.getIfCode()); + } + + @Override + public Oauth2Params queryIsvOauth2Params(String isvNo, String ifCode) { + if (isCache()) { + IsvConfigBy3rdContext isvConfigContext = configContextService.getIsvConfigContext(isvNo); + return isvConfigContext == null ? null : isvConfigContext.getOauth2ParamsByIfCode(ifCode); + } + + PayInterfaceConfig dbRecord = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV_OAUTH2, isvNo, ifCode); + if (dbRecord == null || StringUtils.isEmpty(dbRecord.getIfParams())) { + return null; + } + + return Oauth2Params.factory(ifCode, dbRecord.getIfParams()); + } + + + // 查询参数, 自动判断是否根据商户选择的 infoId进行查询 + public Oauth2Params queryIsvOauth2ParamsByAutoSelectOauth2InfoId(String isvNo, String ifCode, String selectOauth2InfoId) { + if (isCache()) { + IsvConfigBy3rdContext isvConfigContext = configContextService.getIsvConfigContext(isvNo); + if (isvConfigContext == null) { + return null; + } + + // 默认oauth2配置: 逻辑无变化 + if (StringUtils.isEmpty(selectOauth2InfoId)) { + return isvConfigContext.getOauth2ParamsByIfCode(ifCode); + } + + // 选择的其他条目 + return isvConfigContext.queryOauth2ParamsMapByDiyList(selectOauth2InfoId, ifCode); + } + + // selectOauth2InfoId or isvNo + PayInterfaceConfig dbRecord = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV_OAUTH2, StringUtils.defaultIfEmpty(selectOauth2InfoId, isvNo), ifCode); + if (dbRecord == null || StringUtils.isEmpty(dbRecord.getIfParams())) { + return null; + } + + return Oauth2Params.factory(ifCode, dbRecord.getIfParams()); + } + + + @Override + public Oauth2Params queryNormalOauth2Params(String mchNo, String mchAppId, String ifCode) { + if (isCache()) { + MchAppConfigBy3rdContext mchAppConfigBy3rdContext = configContextService.getMchAppConfigContext(mchNo, mchAppId); + return mchAppConfigBy3rdContext == null ? null : mchAppConfigBy3rdContext.getOauth2ParamsByIfCode(ifCode); + } + + PayInterfaceConfig dbRecord = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, mchAppId, ifCode); + if (dbRecord == null || StringUtils.isEmpty(dbRecord.getIfParams())) { + return null; + } + + return Oauth2Params.factory(ifCode, dbRecord.getIfParams()); + } + + @Override + public T queryOauth2Params(String infoType, String infoId, String ifCode, Class cls) { + PayInterfaceConfig dbRecord = payInterfaceConfigService.getByInfoIdAndIfCode(infoType, infoId, ifCode); + + if (dbRecord == null || StringUtils.isEmpty(dbRecord.getIfParams())) { + return null; + } + return Oauth2Params.factory(ifCode, dbRecord.getIfParams(), cls); + } + + public AlipayClientWrapper getAlipayClientWrapper(MchAppConfigContext mchAppConfigContext) { + + if (isCache()) { + return + configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()).getAlipayClientWrapper(); + } + + if (mchAppConfigContext.isIsvsubMch()) { + + AlipayIsvParams alipayParams = (AlipayIsvParams) queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY); + return AlipayClientWrapper.buildAlipayClientWrapper( + alipayParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ALIPAY, AlipayOauth2Params.class) + ); + + } else { + + AlipayNormalMchParams alipayParams = (AlipayNormalMchParams) queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY); + return AlipayClientWrapper.buildAlipayClientWrapper( + alipayParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY, AlipayOauth2Params.class) + ); + + } + + } + + + // 注意: 此函数只能获取oauth2 相关信息, 自动判断 oauth2的选择。 + public AlipayClientWrapper getAlipayClientWrapperByAutoOauth2(MchAppConfigContext mchAppConfigContext, String ifCode) { + + if (isCache()) { + + // 普通商户: 原始无变化 + if (!mchAppConfigContext.isIsvsubMch()) { + return configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()).getAlipayClientWrapper(); + } + + MchAppConfigBy3rdContext mchAppConfigBy3rdContext = configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()); + + String oauth2SelectInfoId = mchAppConfigBy3rdContext.getIsvConfigContext().getOauth2SelectedInfoId().get(ifCode); + + // 无配置 infoId : 逻辑无变化 + if (StringUtils.isEmpty(oauth2SelectInfoId)) { + return mchAppConfigBy3rdContext.getAlipayClientWrapper(); + } + + // 获取服务商的 其他 oauth2 对象 + IsvConfigBy3rdContext isvConfigBy3rdContext = (IsvConfigBy3rdContext) mchAppConfigBy3rdContext.getIsvConfigContext(); + return isvConfigBy3rdContext.getAlipayClientWrapperByOauth2diyMap().get(oauth2SelectInfoId); + + } + + // 以下为: 无缓存 + + if (mchAppConfigContext.isIsvsubMch()) { + + // 1. 查询出该接口是否使用 默认 oauth2条目。 + String oauth2SelectedInfoId = this.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCode); + + // 无配置, 则使用服务商的默认参数, 否则使用配置参数。 + String selectInfoId = StringUtils.isEmpty(oauth2SelectedInfoId) ? mchAppConfigContext.getMchApplyment().getIsvNo() : oauth2SelectedInfoId; + + return AlipayClientWrapper.buildAlipayClientWrapper( + (AlipayIsvParams) null, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, selectInfoId, CS.IF_CODE.ALIPAY, AlipayOauth2Params.class) + ); + + } else { // 普通商户 + + AlipayNormalMchParams alipayParams = (AlipayNormalMchParams) queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY); + return AlipayClientWrapper.buildAlipayClientWrapper( + alipayParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, mchAppConfigContext.getAppId(), CS.IF_CODE.ALIPAY, AlipayOauth2Params.class) + ); + + } + } + + + public ZftpayClientWrapper getZftpayClientWrapper(MchAppConfigContext mchAppConfigContext) { + if (isCache()) { + return configContextService.getIsvConfigContext(mchAppConfigContext.getMchApplyment().getIsvNo()).getZftpayClientWrapper(); + } + + ZftpayIsvParams alipayParams = (ZftpayIsvParams) queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.ZFTPAY); + return ZftpayClientWrapper.buildZftpayClientWrapper(alipayParams); + } + + public ZftpayClientWrapper getZftpayClientWrapper(String isvNo) { + if (isCache()) { + return configContextService.getIsvConfigContext(isvNo).getZftpayClientWrapper(); + } + ZftpayIsvParams alipayParams = (ZftpayIsvParams) queryIsvParams(isvNo, CS.IF_CODE.ZFTPAY); + return ZftpayClientWrapper.buildZftpayClientWrapper(alipayParams); + } + + public WxServiceWrapper getWxServiceWrapper(MchAppConfigContext mchAppConfigContext) { // TODO + + if (isCache()) { + return + configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()).getWxServiceWrapper(); + } + + if (mchAppConfigContext.isIsvsubMch()) { + + WxpayIsvParams wxParams = (WxpayIsvParams) queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY); + return WxServiceWrapper.buildWxServiceWrapper(wxParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY, WxpayOauth2Params.class) + ); + + } else { + + WxpayNormalMchParams wxParams = (WxpayNormalMchParams) queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + return WxServiceWrapper.buildWxServiceWrapper(wxParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY, WxpayOauth2Params.class) + ); + + } + + } + + public WxServiceWrapper getWxServiceWrapper(TransferWalletEntity walletEntity, WxpayIsvParams isvParams) { + return WxServiceWrapper.buildWxServiceWrapper(isvParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, walletEntity.getIsvNo(), CS.IF_CODE.WXPAY, WxpayOauth2Params.class) + ); + } + + + // 注意: 此函数只能获取oauth2 相关信息, 自动判断 oauth2的选择。 + public WxServiceWrapper getWxServiceWrapperByAutoOauth2(MchAppConfigContext mchAppConfigContext, String ifCode) { + + if (isCache()) { + + // 普通商户: 原始无变化 + if (!mchAppConfigContext.isIsvsubMch()) { + return configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()).getWxServiceWrapper(); + } + + MchAppConfigBy3rdContext mchAppConfigBy3rdContext = configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()); + + String oauth2SelectInfoId = mchAppConfigBy3rdContext.getIsvConfigContext().getOauth2SelectedInfoId().get(ifCode); + + // 无配置 infoId : 逻辑无变化 + if (StringUtils.isEmpty(oauth2SelectInfoId)) { + return mchAppConfigBy3rdContext.getWxServiceWrapper(); + } + + // 获取服务商的 其他 oauth2 对象 + IsvConfigBy3rdContext isvConfigBy3rdContext = (IsvConfigBy3rdContext) mchAppConfigBy3rdContext.getIsvConfigContext(); + return isvConfigBy3rdContext.getWxServiceWrapperByOauth2diyMap().get(oauth2SelectInfoId); + + } + + // 以下为: 无缓存 + + // 特约商户 + if (mchAppConfigContext.isIsvsubMch()) { + + // 1. 查询出该接口是否使用 默认 oauth2条目。 + String oauth2SelectedInfoId = this.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCode); + + // 无配置, 则使用服务商的默认参数, 否则使用配置参数。 + String selectInfoId = StringUtils.isEmpty(oauth2SelectedInfoId) ? mchAppConfigContext.getMchApplyment().getIsvNo() : oauth2SelectedInfoId; + + return WxServiceWrapper.buildWxServiceWrapper((WxpayIsvParams) null, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.ISV_OAUTH2, selectInfoId, CS.IF_CODE.WXPAY, WxpayOauth2Params.class) + ); + + } else { // 普通商户 + + WxpayNormalMchParams wxParams = (WxpayNormalMchParams) queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + return WxServiceWrapper.buildWxServiceWrapper(wxParams, + this.queryOauth2Params(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY, WxpayOauth2Params.class) + ); + } + } + + + public PaypalWrapper getPaypalWrapper(MchAppConfigContext mchAppConfigContext) { + + if (isCache()) { + return + configContextService.getMchAppConfigContext(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId()).getPaypalWrapper(); + } + + PpPayNormalMchParams ppPayNormalMchParams = (PpPayNormalMchParams) queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.PPPAY); + return PaypalWrapper.buildPaypalWrapper(ppPayNormalMchParams); + + } + + + /** + * 根据页面, 获取到 ifCode + **/ + public String queryIfCodeByPageType(MchAppConfigContext mchAppConfigContext, String currentPageType) { + + if (StringUtils.isEmpty(currentPageType)) { + return null; + } + + String wayCode = ""; + if (currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_H5)) { + + wayCode = CS.PAY_WAY_CODE.ALI_JSAPI; + + } else if (currentPageType.equals(QRCodeParams.PAGE_TYPE_ALIPAY_LITE)) { + wayCode = CS.PAY_WAY_CODE.ALI_LITE; + + } else if (currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_H5)) { + wayCode = CS.PAY_WAY_CODE.WX_JSAPI; + + } else if (currentPageType.equals(QRCodeParams.PAGE_TYPE_WECHAT_LITE)) { + wayCode = CS.PAY_WAY_CODE.WX_LITE; + } + + MchPayPassage payPassage = mchPayPassageService.findMchPayPassage(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), wayCode); + return payPassage == null ? null : payPassage.getIfCode(); + } + + + /*** + * + * 查询 服务商 or 服务商配置的 auth2记录 + * 如果服务商配置了, 那么选择服务商的, + * 如果没有配置, 那么使用服务商配置(原逻辑) + * **/ + public String queryAgentOrIsvSelectOauth2InfoId(String agentNo, String isvNo, String ifCode) { + + // 没有服务商 ( 原逻辑 ) + if (StringUtils.isEmpty(agentNo)) { + return payInterfaceConfigService.queryIsvSelectOauth2InfoId(isvNo, ifCode); + } + + String result = payInterfaceConfigService.queryAgentSelectOauth2InfoId(agentNo, ifCode); + + // 服务商配置不为空, 说明有配置( 选择服务商默认也是有值的 ) + if (StringUtils.isNotEmpty(result)) { + return result; + } + + // 使用服务商配置 + return payInterfaceConfigService.queryIsvSelectOauth2InfoId(isvNo, ifCode); + } + + /*** + * 方法重载 + * **/ + public String queryAgentOrIsvSelectOauth2InfoId(com.jeequan.jeepay.core.entity.MchApplyment mchApplyment, String ifCode) { + return queryAgentOrIsvSelectOauth2InfoId(mchApplyment.getAgentNo(), mchApplyment.getIsvNo(), ifCode); + } + + + /** + * 查询服务商进件特殊参数 + */ + public JSONObject queryAgentApplymentExtParams(String agentNo, String ifCode) { + + PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.AGENT, agentNo, ifCode); + if (payInterfaceConfig == null || StringUtils.isEmpty(payInterfaceConfig.getApplymentExtParams())) { + return new JSONObject(); + } + return JSON.parseObject(payInterfaceConfig.getApplymentExtParams()); + } + + + @Override + public MchAppConfigContext queryMchInfoAndAppInfoV2(String mchNo, String mchAppId, String applyId) { + MchAppConfigContext mchAppConfigContext = null; + if (StringUtils.isNotEmpty(mchAppId)) { + mchAppConfigContext = queryMchInfoAndAppInfo(mchNo, mchAppId); + } + if (StringUtils.isEmpty(applyId)) { + MchStore mchStore = mchStoreService.queryDefaultStore(mchNo); + //获取默认门店绑定的applyId + applyId = mchStore.getMchApplyId(); + } + MchApplyment mchApplyment = mchApplymentService.getById(applyId); + if (mchAppConfigContext == null) { + mchAppConfigContext = queryMchInfoAndAppInfo(mchNo, mchApplyment.getAutoConfigMchAppId()); + } + mchAppConfigContext.setMchApplyment(mchInfoConverter.toModel(mchApplyment)); + mchAppConfigContext.getMchInfo().setIsvNo(mchApplyment.getIsvNo()).setMchName(mchApplyment.getMchFullName()).setMchShortName(mchApplyment.getMchShortName()); + return mchAppConfigContext; + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextService.java new file mode 100644 index 0000000..fbbb181 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ConfigContextService.java @@ -0,0 +1,428 @@ +package com.jeequan.jeepay.thirdparty.service; + +import com.jeequan.jeepay.converter.MchInfoConverter; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.IsvInfo; +import com.jeequan.jeepay.core.entity.MchApp; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.interfaces.IConfigContextService; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.context.MchInfoConfigContext; +import com.jeequan.jeepay.core.model.oauth2.AlipayOauth2Params; +import com.jeequan.jeepay.core.model.oauth2.Oauth2Params; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.db.entity.MchAppEntity; +import com.jeequan.jeepay.db.entity.PayInterfaceConfig; +import com.jeequan.jeepay.service.impl.*; +import com.jeequan.jeepay.thirdparty.model.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/* +* 商户/服务商 配置信息上下文服务 +* +* @author terrfly +* +* @date 2021/6/8 17:41 +*/ +@Slf4j +@Service +public class ConfigContextService implements IConfigContextService { + + /** <商户ID, 商户配置项> **/ + private static final Map mchInfoConfigContextMap = new ConcurrentHashMap<>(); + + /** <应用ID, 商户配置上下文> **/ + private static final Map mchAppConfigContextMap = new ConcurrentHashMap<>(); + + /** <服务商号, 服务商配置上下文> **/ + private static final Map isvConfigContextMap = new ConcurrentHashMap<>(); + + @Autowired private MchInfoService mchInfoService; + @Autowired private MchAppService mchAppService; + @Autowired private IsvInfoService isvInfoService; + @Autowired private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private MchPayInterfaceConfigService mchPayInterfaceConfigService; + @Autowired private MchInfoConverter mchInfoConverter; + + + /** 获取 [商户配置信息] **/ + public MchInfoConfigContext getMchInfoConfigContext(String mchNo){ + + MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo); + + //无此数据, 需要初始化 + if(mchInfoConfigContext == null){ + initMchInfoConfigContext(mchNo); + } + + return mchInfoConfigContextMap.get(mchNo); + } + + /** 获取 [商户应用支付参数配置信息] **/ + public MchAppConfigBy3rdContext getMchAppConfigContext(String mchNo, String appId){ + + MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId); + + //无此数据, 需要初始化 + if(mchAppConfigContext == null){ + initMchAppConfigContext(mchNo, appId); + } + + return mchAppConfigContextMap.get(appId); + } + + /** 获取 [ISV支付参数配置信息] **/ + public IsvConfigBy3rdContext getIsvConfigContext(String isvNo){ + + IsvConfigBy3rdContext isvConfigContext = isvConfigContextMap.get(isvNo); + + //无此数据, 需要初始化 + if(isvConfigContext == null){ + initIsvConfigContext(isvNo); + } + + return isvConfigContextMap.get(isvNo); + } + + + /** 初始化 [商户配置信息] **/ + @Override + public synchronized void initMchInfoConfigContext(String mchNo){ + + if(!isCache()){ // 当前系统不进行缓存 + return ; + } + + //商户主体信息 + MchInfo mchInfo = mchInfoService.getById(mchNo); + if(mchInfo == null){ // 查询不到商户主体, 可能已经删除 + + MchInfoConfigContext mchInfoConfigContext = mchInfoConfigContextMap.get(mchNo); + + // 删除所有的商户应用 + if(mchInfoConfigContext != null){ + mchInfoConfigContext.getAppMap().forEach((k, v) -> mchAppConfigContextMap.remove(k)); + } + + mchInfoConfigContextMap.remove(mchNo); + return ; + } + + MchInfoConfigContext mchInfoConfigContext = new MchInfoConfigContext(); + + // 设置商户信息 + mchInfoConfigContext.setMchNo(mchInfo.getMchNo()); + mchInfoConfigContext.setMchType(mchInfo.getType()); + mchInfoConfigContext.setMchInfo(mchInfo); + mchAppService.lambdaQuery().list().forEach(mchApp -> { + MchApp model = mchInfoConverter.toModel(mchApp); + //1. 更新商户内appId集合 + mchInfoConfigContext.putMchApp(model); + + MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(mchApp.getAppId()); + if(mchAppConfigContext != null){ + mchAppConfigContext.setMchApp(model); + mchAppConfigContext.setMchNo(mchInfo.getMchNo()); + mchAppConfigContext.setMchType(mchInfo.getType()); + mchAppConfigContext.setMchInfo(mchInfo); + } + }); + + mchInfoConfigContextMap.put(mchNo, mchInfoConfigContext); + } + + /** 初始化 [商户应用支付参数配置信息] **/ + @Override + public synchronized void initMchAppConfigContext(String mchNo, String appId){ + + if(!isCache()){ // 当前系统不进行缓存 + return ; + } + + // 获取商户的配置信息 + MchInfoConfigContext mchInfoConfigContext = getMchInfoConfigContext(mchNo); + if(mchInfoConfigContext == null){ // 商户信息不存在 + return; + } + + // 查询商户应用信息主体 + MchAppEntity dbMchApp = mchAppService.getById(appId); + + //DB已经删除 + if(dbMchApp == null){ + mchAppConfigContextMap.remove(appId); //清除缓存信息 + mchInfoConfigContext.getAppMap().remove(appId); //清除主体信息中的appId + return ; + } + + + // 商户应用mchNo 与参数不匹配 + if(!dbMchApp.getMchNo().equals(mchNo)){ + return; + } + + MchApp model = mchInfoConverter.toModel(dbMchApp); + //更新商户信息主体中的商户应用 + mchInfoConfigContext.putMchApp(model); + + //商户主体信息 + MchInfo mchInfo = mchInfoConfigContext.getMchInfo(); + MchAppConfigBy3rdContext mchAppConfigContext = new MchAppConfigBy3rdContext(); + + // 设置商户信息 + mchAppConfigContext.setAppId(appId); + mchAppConfigContext.setMchNo(mchInfo.getMchNo()); + mchAppConfigContext.setMchType(mchInfo.getType()); + mchAppConfigContext.setMchInfo(mchInfo); + mchAppConfigContext.setMchApp(model); + + // 查询商户的所有支持的参数配置 + List allConfigList = payInterfaceConfigService.list(PayInterfaceConfig.gw() + .select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams) + .eq(PayInterfaceConfig::getState, CS.YES) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .eq(PayInterfaceConfig::getInfoId, appId) + ); + + // !! 无论 普通商户 或者 特约商户 都有可能包含 oauth2参数 !! + // 查询支付宝的 oauth2配置; + PayInterfaceConfig alipayOauth2Config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, appId, CS.IF_CODE.ALIPAY); + AlipayOauth2Params alipayOauth2Params = Oauth2Params.factory(CS.IF_CODE.ALIPAY, (alipayOauth2Config == null ? null : alipayOauth2Config.getIfParams()), AlipayOauth2Params.class); + if(alipayOauth2Params != null){ + mchAppConfigContext.getOauth2ParamsMap().put(CS.IF_CODE.ALIPAY, alipayOauth2Params); + } + + // 查询微信的 oauth2配置; + PayInterfaceConfig wxpayOauth2Config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.MCH_APP_OAUTH2, appId, CS.IF_CODE.WXPAY); + WxpayOauth2Params wxpayOauth2Params = Oauth2Params.factory(CS.IF_CODE.WXPAY, (wxpayOauth2Config == null ? null : wxpayOauth2Config.getIfParams()), WxpayOauth2Params.class); + if(wxpayOauth2Params != null){ + mchAppConfigContext.getOauth2ParamsMap().put(CS.IF_CODE.WXPAY, wxpayOauth2Params); + } + + // 普通商户 + if(mchInfo.getType() == CS.MCH_TYPE_NORMAL){ + + for (PayInterfaceConfig payInterfaceConfig : allConfigList) { + mchAppConfigContext.getNormalMchParamsMap().put( + payInterfaceConfig.getIfCode(), + NormalMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()) + ); + } + + //放置alipay client + AlipayNormalMchParams alipayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.ALIPAY, AlipayNormalMchParams.class); + if(alipayParams != null || alipayOauth2Params != null){ + mchAppConfigContext.setAlipayClientWrapper(AlipayClientWrapper.buildAlipayClientWrapper(alipayParams, alipayOauth2Params)); + } + + //放置 wxJavaService + WxpayNormalMchParams wxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(CS.IF_CODE.WXPAY, WxpayNormalMchParams.class); + if(wxpayParams != null || wxpayOauth2Params != null){ + mchAppConfigContext.setWxServiceWrapper(WxServiceWrapper.buildWxServiceWrapper(wxpayParams, wxpayOauth2Params)); + } + + + }else{ //服务商模式商户 + for (PayInterfaceConfig payInterfaceConfig : allConfigList) { + mchAppConfigContext.getIsvsubMchParamsMap().put( + payInterfaceConfig.getIfCode(), + IsvsubMchParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()) + ); + } + + //TODO 商户现在会关联多个服务商,不清楚后续操作的情况下,先屏蔽以下代码 +// mchAppConfigContext.setIsvConfigContext(getIsvConfigContext(mchInfo.getIsvNo())); + + } + + mchAppConfigContextMap.put(appId, mchAppConfigContext); + } + + + /** 初始化 [ISV支付参数配置信息] **/ + @Override + public synchronized void initIsvConfigContext(String isvNo){ + + if(!isCache()){ // 当前系统不进行缓存 + return ; + } + + //查询出所有商户的配置信息并更新 +// List mchNoList = new ArrayList<>(); +// mchInfoService.list(com.jeequan.jeepay.db.entity.MchInfo.gw().select(MchInfo::getMchNo).eq(MchInfo::getIsvNo, isvNo)).forEach(r -> mchNoList.add(r.getMchNo())); +// +// // 查询出所有 所属当前服务商的所有应用集合 +// List mchAppIdList = new ArrayList<>(); +// if(!mchNoList.isEmpty()){ +// mchAppService.lambdaQuery().select(MchAppEntity::getAppId).in(MchAppEntity::getMchNo, mchNoList).list() +// .forEach(r -> mchAppIdList.add(r.getAppId())); +// } + + IsvConfigBy3rdContext isvConfigContext = new IsvConfigBy3rdContext(); + IsvInfo isvInfo = isvInfoService.getById(isvNo); + if(isvInfo == null){ + +// for (String appId : mchAppIdList) { +// //将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针) +// MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId); +// if(mchAppConfigContext != null){ +// mchAppConfigContext.setIsvConfigContext(null); +// } +// } + + isvConfigContextMap.remove(isvNo); // 服务商有商户不可删除, 此处不再更新商户下的配置信息 + return ; + } + + // 设置商户信息 + isvConfigContext.setIsvNo(isvInfo.getIsvNo()); + isvConfigContext.setIsvInfo(isvInfo); + + // 查询服务商的所有支持的参数配置 + List allConfigList = payInterfaceConfigService.list(PayInterfaceConfig.gw() + .select(PayInterfaceConfig::getIfCode, PayInterfaceConfig::getIfParams, PayInterfaceConfig::getOauth2InfoId) + .eq(PayInterfaceConfig::getState, CS.YES) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(PayInterfaceConfig::getInfoId, isvNo) + ); + + List allConfigList2 = mchPayInterfaceConfigService.lambdaQuery() + .select(com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getIfCode, com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getIfParams, com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getOauth2InfoId) + .eq(com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getState, CS.YES) + .eq(com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV) + .eq(com.jeequan.jeepay.db.entity.MchPayInterfaceConfig::getInfoId, isvNo).list(); + + // 同时存储两张表的数据 + for (PayInterfaceConfig payInterfaceConfig : allConfigList) { + isvConfigContext.getIsvParamsMap().put( + payInterfaceConfig.getIfCode(), + IsvParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()) + ); + + // 选择的oauth2条目 + isvConfigContext.getOauth2SelectedInfoId().put(payInterfaceConfig.getIfCode(), payInterfaceConfig.getOauth2InfoId()); + } + + + for (com.jeequan.jeepay.db.entity.MchPayInterfaceConfig payInterfaceConfig : allConfigList2) { + isvConfigContext.getIsvParamsMap().put( + payInterfaceConfig.getId(), + IsvParams.factory(payInterfaceConfig.getIfCode(), payInterfaceConfig.getIfParams()) + ); + } + + // 设置默认的oauth2参数 + this.commonsPutIsvOauth2Map(isvConfigContext, isvNo, true); + + // 查询出所有的 其他 自定义 oauth2参数。 并去重。 + String infoIdLike = isvNo + "_LIST_"; + List diyList = + payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getInfoId) + .like(PayInterfaceConfig::getInfoId, infoIdLike).eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.ISV_OAUTH2)); + + // 去重 + Set infoIdSet = new HashSet<>(); + for (PayInterfaceConfig item : diyList) { + infoIdSet.add(item.getInfoId()); + } + + // 设置 diy 的oauth2参数 + for (String infoId : infoIdSet) { + this.commonsPutIsvOauth2Map(isvConfigContext, infoId, false); + } + + + isvConfigContextMap.put(isvNo, isvConfigContext); + + //查询出所有商户的配置信息并更新 +// for (String appId : mchAppIdList) { +// //将更新已存在缓存的商户配置信息 (每个商户下存储的为同一个 服务商配置的对象指针) +// MchAppConfigContext mchAppConfigContext = mchAppConfigContextMap.get(appId); +// if(mchAppConfigContext != null){ +// mchAppConfigContext.setIsvConfigContext(isvConfigContext); +// } +// } + } + + + private boolean isCache(){ + return SysConfigService.IS_USE_CACHE; + } + + // 通用放置 oauth2参数的函数。 + private void commonsPutIsvOauth2Map(IsvConfigBy3rdContext isvConfigContext, String infoId, boolean isDefault){ + + // 查询支付宝的 oauth2配置; + PayInterfaceConfig alipayOauth2Config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV_OAUTH2, infoId, CS.IF_CODE.ALIPAY); + AlipayOauth2Params alipayOauth2Params = Oauth2Params.factory(CS.IF_CODE.ALIPAY, (alipayOauth2Config == null ? null : alipayOauth2Config.getIfParams()), AlipayOauth2Params.class); + if(alipayOauth2Params != null){ + + if(isDefault){ + isvConfigContext.getOauth2ParamsMap().put(CS.IF_CODE.ALIPAY, alipayOauth2Params); + }else{ + isvConfigContext.putOauth2ParamsMapByDiyList(infoId, CS.IF_CODE.ALIPAY, alipayOauth2Params); + } + + } + + // 查询微信的 oauth2配置; + PayInterfaceConfig wxpayOauth2Config = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV_OAUTH2, infoId, CS.IF_CODE.WXPAY); + WxpayOauth2Params wxpayOauth2Params = Oauth2Params.factory(CS.IF_CODE.WXPAY, (wxpayOauth2Config == null ? null : wxpayOauth2Config.getIfParams()), WxpayOauth2Params.class); + if(wxpayOauth2Params != null){ + + if(isDefault){ + isvConfigContext.getOauth2ParamsMap().put(CS.IF_CODE.WXPAY, wxpayOauth2Params); + }else{ + isvConfigContext.putOauth2ParamsMapByDiyList(infoId, CS.IF_CODE.WXPAY, wxpayOauth2Params); + } + + } + + //放置alipay client + AlipayIsvParams alipayParams = isDefault ? isvConfigContext.getIsvParams(CS.IF_CODE.ALIPAY, AlipayIsvParams.class) : null; + if(alipayParams != null || alipayOauth2Params != null){ + + if(isDefault){ + isvConfigContext.setAlipayClientWrapper(AlipayClientWrapper.buildAlipayClientWrapper(alipayParams, alipayOauth2Params)); + }else{ + isvConfigContext.getAlipayClientWrapperByOauth2diyMap().put(infoId, AlipayClientWrapper.buildAlipayClientWrapper(alipayParams, alipayOauth2Params)); + } + + } + + //放置zftpay client + ZftpayIsvParams zftpayParams = isDefault ? isvConfigContext.getIsvParams(CS.IF_CODE.ZFTPAY, ZftpayIsvParams.class) : null; + if(zftpayParams != null){ + isvConfigContext.setZftpayClientWrapper(ZftpayClientWrapper.buildZftpayClientWrapper(zftpayParams)); + } + + //放置 wxJavaService + WxpayIsvParams wxpayParams = isDefault ? isvConfigContext.getIsvParams(CS.IF_CODE.WXPAY, WxpayIsvParams.class) : null; + if(wxpayParams != null || wxpayOauth2Params != null){ + + if(isDefault){ + isvConfigContext.setWxServiceWrapper(WxServiceWrapper.buildWxServiceWrapper(wxpayParams, wxpayOauth2Params)); + }else{ + isvConfigContext.getWxServiceWrapperByOauth2diyMap().put(infoId, WxServiceWrapper.buildWxServiceWrapper(wxpayParams, wxpayOauth2Params)); + } + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/SaasConfigService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/SaasConfigService.java new file mode 100644 index 0000000..f7d894f --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/SaasConfigService.java @@ -0,0 +1,127 @@ +package com.jeequan.jeepay.thirdparty.service; + +import com.jeequan.jeepay.db.entity.AgentConfig; +import com.jeequan.jeepay.service.impl.AgentConfigService; +import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean; +import freemarker.template.Configuration; +import freemarker.template.Template; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileWriter; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class SaasConfigService { + + @Autowired + private AgentConfigService agentConfigService; + + @Autowired + private ChannelCertConfigKitBean channelCertConfigKitBean; + + @Autowired + private Configuration configuration; + + /** + * 代理域名配置 + * + * @param agentNo 代理商编号 + * @param agentSiteUrl 代理域名链接 + * @param agentSiteCrtUrl 域名SSL证书文件链接 + * @param agentSitePriKeyUrl 域名SSL私钥链接 + * @param mchSiteUrl 商户域名链接 + * @param mchSiteCrtUrl 商户SSL证书文件链接 + * @param mchSitePriKeyUrl 商户SSL私钥链接 + */ + public void siteConfig( + String agentNo, + String agentSiteUrl, String agentSiteCrtUrl, String agentSitePriKeyUrl, + String mchSiteUrl, String mchSiteCrtUrl, String mchSitePriKeyUrl) { + + saveData(agentNo, agentSiteUrl, agentSiteCrtUrl, agentSitePriKeyUrl, "nginx_agent.ftl", "agentSiteUrl", "agentSiteCrtUrl", "agentSitePriKeyUrl"); + saveData(agentNo, mchSiteUrl, mchSiteCrtUrl, mchSitePriKeyUrl, "nginx_mch.ftl", "mchSiteUrl", "mchSiteCrtUrl", "mchSitePriKeyUrl"); + } + + private void saveData(String agentNo, String agentSiteUrl, String agentSiteCrtUrl, String agentSitePriKeyUrl, String nginxFtl, String configKey1, String configKey2, String configKey3) { + agentSiteUrl = agentSiteUrl.replace("http://", ""); + agentSiteUrl = agentSiteUrl.replace("https://", ""); + + AgentConfig exist = agentConfigService.lambdaQuery().eq(AgentConfig::getAgentNo, agentNo) + .eq(AgentConfig::getConfigKey, configKey1) + .eq(AgentConfig::getGroupKey, "agentSiteConfig").one(); + + File existConfigFile = null; + + if (exist != null && !exist.getConfigVal().equals(agentSiteUrl)) { + // 链接发生变化,则将需要将以前的文件改名 + existConfigFile = new File("/www/server/panel/vhost/nginx/", exist.getConfigVal() + ".conf"); + } + + // 第一次保存数据 + + AgentConfig config = new AgentConfig(); + config.setAgentNo(agentNo); + config.setConfigKey(configKey1); + config.setGroupKey("agentSiteConfig"); + config.setConfigVal(agentSiteUrl); + agentConfigService.saveOrUpdateConfig(config); + + config = new AgentConfig(); + config.setAgentNo(agentNo); + config.setConfigKey(configKey2); + config.setGroupKey("agentSiteConfig"); + config.setConfigVal(agentSiteCrtUrl); + agentConfigService.saveOrUpdateConfig(config); + + config = new AgentConfig(); + config.setAgentNo(agentNo); + config.setConfigKey(configKey3); + config.setGroupKey("agentSiteConfig"); + config.setConfigVal(agentSitePriKeyUrl); + agentConfigService.saveOrUpdateConfig(config); + + String agentSiteCrtPath = channelCertConfigKitBean.getCertFilePath(agentSiteCrtUrl); + String agentSitePriKeyPath = channelCertConfigKitBean.getCertFilePath(agentSitePriKeyUrl); + + try { + Template template = configuration.getTemplate(nginxFtl); + + Map param = new HashMap<>(); + param.put("agentSiteUrl", agentSiteUrl); + param.put("agentSiteCrtPath", agentSiteCrtPath); + param.put("agentSitePriKeyPath", agentSitePriKeyPath); + // 将配置文件生成到宝塔的nginx配置目录下 + File configFile = new File("/www/server/panel/vhost/nginx/", agentSiteUrl + ".conf"); + if (!configFile.exists()) { + File parentFile = configFile.getParentFile(); + if (!parentFile.exists()) { + parentFile.mkdirs(); + } + configFile.createNewFile(); + } + FileWriter sw = new FileWriter(configFile); + template.process(param, sw); + + // 以前的文件改名 + if (existConfigFile != null && existConfigFile.exists()) { + String c = existConfigFile.getAbsolutePath(); + // 加个时间戳,防止保存时重复 + File bak = new File(c + "." + System.currentTimeMillis() +".bak"); + existConfigFile.renameTo(bak); + } + } catch (Exception e) { + log.info("生成模板文件异常", e); + } + + try { + Runtime.getRuntime().exec("nginx -s reload"); + } catch (Exception e) { + log.info("刷新nginx配置异常", e); + } + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/AliOCRApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/AliOCRApiService.java new file mode 100644 index 0000000..8c5d1ad --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/AliOCRApiService.java @@ -0,0 +1,165 @@ +package com.jeequan.jeepay.thirdparty.service.ocr; + +import com.alibaba.fastjson.JSONObject; +import com.aliyun.ocr_api20210707.Client; +import com.aliyun.ocr_api20210707.models.*; +import com.aliyun.teaopenapi.models.Config; +import com.jeequan.jeepay.core.interfaces.IOCRApiService; +import com.jeequan.jeepay.core.model.DBOCRConfig; +import com.jeequan.jeepay.core.model.OCRImgParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.util.OCRUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 阿里OCR接口 + * + * @author xiaoyu + * + * @date 2022/1/11 15:31 + */ +@Slf4j +@Service +public class AliOCRApiService implements IOCRApiService { + + @Autowired private SysConfigService sysConfigService; + + private DBOCRConfig getocrConfig() { + DBOCRConfig dbocrConfig = sysConfigService.getOcrConfig(); + return dbocrConfig; + } + + /** + * @author: xiaoyu + * @date: 2022/1/12 11:16 + * @describe: 身份证识别信息 + */ + @Override + public OCRImgParams getIdCardInfo(String imgUrl){ + RecognizeIdcardRequest request = new RecognizeIdcardRequest(); + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + Client client = createClient(); + // 图片地址 + request.setUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + RecognizeIdcardResponse response = client.recognizeIdcard(request); + + // 阿里云OCR返回JSON数据参数 + JSONObject jsonResult = JSONObject.parseObject(response.getBody().getData()); + log.info("【OCR识别】response-header:{}, response-body:{}", response.getHeaders(), jsonResult); + + JSONObject dataJson = jsonResult.getJSONObject("data"); + // 正面照数据 + JSONObject faceJson = dataJson.getJSONObject("face"); + JSONObject backJson = dataJson.getJSONObject("back"); + if (faceJson != null) { + JSONObject paramsJson = faceJson.getJSONObject("data"); + // 姓名 + ocrImgParams.setIdcardName(paramsJson.getString("name")); + // 性别 + ocrImgParams.setIdcardSex(paramsJson.getString("sex")); + // 地址 + ocrImgParams.setIdcardAddress(paramsJson.getString("address")); + // 身份证号 + ocrImgParams.setIdcardNo(paramsJson.getString("idNumber")); + } + if (backJson != null) { + JSONObject paramsJson = backJson.getJSONObject("data"); + // 签发机关 + String issueAuthority = paramsJson.getString("issueAuthority"); + // 有效日期 [日期格式转换] + String validPeriod = paramsJson.getString("validPeriod"); + OCRUtil.setIdCardDate(validPeriod, ocrImgParams); + } + }catch (Exception e) { + log.info("【阿里云OCR】身份证识别异常", e); + } + return ocrImgParams; + } + + @Override + public OCRImgParams getBusinessLicenceInfo(String imgUrl) { + RecognizeBusinessLicenseRequest request = new RecognizeBusinessLicenseRequest(); + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + Client client = createClient(); + // 图片地址 + request.setUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + RecognizeBusinessLicenseResponse response = client.recognizeBusinessLicense(request); + JSONObject jsonResult = JSONObject.parseObject(response.getBody().getData()); + log.info("【OCR识别】response-header:{}, response-body:{}", response.getHeaders(), jsonResult); + + // 阿里云OCR返回JSON数据参数 + JSONObject dataJson = jsonResult.getJSONObject("data"); + // 社会统一信用代码 + ocrImgParams.setLicenseNo(dataJson.getString("creditCode")); + // 公司名称 + ocrImgParams.setMchFullName(dataJson.getString("companyName")); + // 有效期 + OCRUtil.setLicenseDateAli(dataJson, ocrImgParams); + // 公司地址 + ocrImgParams.setLicenseAddress(dataJson.getString("businessAddress")); + // 法人 + ocrImgParams.setLicensePerson(dataJson.getString("legalPerson")); + // 经营范围 + ocrImgParams.setLicenseBusiness(dataJson.getString("businessScope")); + }catch (Exception e) { + log.info("【阿里云OCR】营业执照识别异常", e); + } + return ocrImgParams; + } + + @Override + public OCRImgParams getBankCardInfo(String imgUrl) { + RecognizeBankCardRequest request = new RecognizeBankCardRequest(); + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + Client client = createClient(); + // 图片地址 + request.setUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + RecognizeBankCardResponse response = client.recognizeBankCard(request); + JSONObject jsonResult = JSONObject.parseObject(response.getBody().getData()); + log.info("【OCR识别】response-header:{}, response-body:{}", response.getHeaders(), jsonResult); + + // 阿里云OCR返回JSON数据参数 + JSONObject dataJson = jsonResult.getJSONObject("data"); + ocrImgParams.setSettAccountBankName(dataJson.getString("bankName")); + ocrImgParams.setSettAccountNo(dataJson.getString("cardNumber")); + }catch (Exception e) { + log.info("【阿里云OCR】银行卡识别异常", e); + } + return ocrImgParams; + } + + + /** + * @author: xiaoyu + * @date: 2022/1/11 15:50 + * @describe: 初始化账号Client + */ + private Client createClient() { + try { + Config config = new Config(); + String accessKeyId = getocrConfig().getAliAccessKeyId(); + String accessKeySecret = getocrConfig().getAliAccessKeySecret(); + config.setAccessKeyId(accessKeyId); + config.setAccessKeySecret(accessKeySecret); + config.setEndpoint("ocr-api.cn-hangzhou.aliyuncs.com"); + return new Client(config); + }catch (Exception e) { + log.error("阿里云OCR初始化Client异常", e); + } + return null; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduClient.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduClient.java new file mode 100644 index 0000000..8d3e30a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduClient.java @@ -0,0 +1,346 @@ +package com.jeequan.jeepay.thirdparty.service.ocr; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.AllArgsConstructor; +import lombok.Cleanup; +import lombok.Data; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2023/10/24 16:08 + */ +@Slf4j +@Data +public class BaiduClient { + + private String apiKey; + + private String secretKey; + + private String accessToken; + + /** + * accessToken 获取url + */ + private final String AUTH_URL = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET"; + + /** + * 营业执照url + */ + private final String BL_CARD_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/business_license?access_token=ACCESS_TOKEN"; + + /** + * 身份证识别url + */ + private final String ID_CARD_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=ACCESS_TOKEN"; + + /** + * 银行卡识别url + */ + private final String BK_CARD_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/bankcard?access_token=ACCESS_TOKEN"; + + public final String CLIENT_ID_NAME = "CLIENT_ID"; + + public final String CLIENT_SECRET_NAME = "CLIENT_SECRET"; + + public final String BAUDU_AUTH_TOKEN_NAME = "ACCESS_TOKEN"; + + public final String BAUDU_ERROR_CODE = "error_code"; + + public final String BAUDU_ERROR_DESC = "error_description"; + + public final String ACCESS_TOKEN_CODE = "access_token"; + + public final Integer DEFAULT_EXPIRE_NUM = 30; + + + @Data + public class IdCard { + /** + * 名字 + */ + public String name; + + /** + * 号码 + */ + public String idNum; + + public String sex; + /** + * 有效期 + */ + public String validDate; + + public String address; + } + + @Data + public class BusinessLicence { + /** + * 营业执照编号 + */ + public String busNo; + + /** + * 营业执照名称 + */ + public String name; + + /** + * 法人姓名 + */ + public String person; + + /** + * 有效期 + */ + public String address; + + /** + * 经营范围 + */ + public String business; + + /** + * 有效期 + */ + public String startDate; + + /** + * 截止日期 + */ + public String endDate; + + public BusinessLicence(String busNo, String name, String person, String address, String startDate, String endDate, String business) { + this.busNo = busNo; + this.name = name; + this.person = person; + this.address = address; + this.startDate = startDate; + this.endDate = endDate; + this.business = business; + } + } + + @Data + public class BankCard { + /** + * 银行名称 + */ + public String bankName; + + /** + * 卡号 + */ + public String cardNo; + + public BankCard(String bankName, String cardNo) { + this.bankName = bankName; + this.cardNo = cardNo; + } + } + + @Getter + @AllArgsConstructor + public enum BankCardStatus { + + NO(0, "当前卡片无法识别,请上传比较清晰的图片!"), + DEBIT_CARD(1, "借记卡"), + CREDIT_CARD(2, "贷记卡"), + ZHUN_CREDIT_CARD(3, "准贷记卡"), + PREPAID_CARD(4, "预付费卡"); + + private int value; + + private String desc; + + public static void checkCardType(int value) { + boolean flag = false; + String text = ""; + if (value == NO.getValue()) { + text = NO.getDesc(); + } else { + BankCardStatus[] values = values(); + for (BankCardStatus val : values) { + if (val.getValue() == value) { + flag = true; + } else { + text = "只能上传" + DEBIT_CARD.getDesc(); + } + } + } + if (!flag) { + throw new BizException(text); + } + } + } + + public BaiduClient(String apiKey, String secretKey) { + this.apiKey = apiKey; + this.secretKey = secretKey; + this.accessToken = getAuthAccessToken(); + } + + /** + * 获取授权token + * + * @return + */ + public String getAuthAccessToken() { + String reqUrl = AUTH_URL.replace(CLIENT_ID_NAME, this.getApiKey()).replace(CLIENT_SECRET_NAME, this.getSecretKey()); + String body = HttpRequest.get(reqUrl).execute().body(); + if (StringUtils.isEmpty(body)) { + throw new BizException("百度授权接口异常"); + } + JSONObject result = JSON.parseObject(body); + String access_token = result.getString(ACCESS_TOKEN_CODE); + if (StringUtils.isEmpty(access_token)) { + throw new BizException("百度授权接口异常,异常信息:" + result.getString(BAUDU_ERROR_DESC)); + } + return access_token; + } + + /** + * 营业执照OCR + * + * @param url + * @return + */ + public BusinessLicence blOCR(String url) { + String reqUrl = BL_CARD_URL.replace(BAUDU_AUTH_TOKEN_NAME, this.getAccessToken()); + String body; + try { + @Cleanup HttpResponse execute = HttpRequest.post(reqUrl) + .form("url", url) + .execute(); + body = execute.body(); + } catch (Exception e) { + log.info("OCR接口异常", e); + throw new BizException("OCR接口异常, 请联系平台管理人员"); + } + + try { + JSONObject result = initResult(body); + String name = result.getJSONObject("单位名称").getString("words"); + String person = result.getJSONObject("法人").getString("words"); + String busNo = result.getJSONObject("社会信用代码").getString("words"); + String business = result.getJSONObject("经营范围").getString("words"); + String address = result.getJSONObject("地址").getString("words"); + String startDate = DateUtil.format(DateUtil.parse(result.getJSONObject("成立日期").getString("words"), "yyyy年MM月dd日"), "yyyy-MM-dd"); + String endDate = result.getJSONObject("有效期").getString("words"); + if (StringUtils.isNotEmpty(endDate) && "无".equals(endDate)) { + endDate = "长期"; + } + BusinessLicence bl = new BusinessLicence(busNo, name, person, address, startDate, endDate, business); + + return bl; + } catch (Exception e) { + log.info("OCR识别失败", e); + throw new BizException("OCR识别失败, 请手动相关补充资料"); + } + } + + /** + * 身份证OCR + * + * @param url + * @return + */ + public IdCard icOCR(String url) { + String reqUrl = ID_CARD_URL.replace(BAUDU_AUTH_TOKEN_NAME, this.getAccessToken()); + String body; + try { + @Cleanup HttpResponse execute = HttpRequest.post(reqUrl) + .form("url", url) + .form("id_card_side", "front") + .execute(); + body = execute.body(); + } catch (Exception e) { + log.info("OCR接口异常", e); + throw new BizException("OCR接口异常, 请联系平台管理人员"); + } + + JSONObject result = initResult(body); + JSONObject nameObj = result.getJSONObject("姓名"); + IdCard idCard = new IdCard(); + try { + if (nameObj != null) { + String cardName = nameObj.getString("words"); + String cardNo = result.getJSONObject("公民身份号码").getString("words"); + String address = result.getJSONObject("住址").getString("words"); + idCard.setName(cardName); + idCard.setIdNum(cardNo); + idCard.setAddress(address); + return idCard; + } else { + String startDate = result.getJSONObject("签发日期").getString("words"); + String endDate = result.getJSONObject("失效日期").getString("words"); + idCard.setValidDate(startDate + "-" + endDate); + return idCard; + } + } catch (Exception e) { + log.info("OCR识别失败", e); + throw new BizException("OCR识别失败, 请手动相关补充资料"); + } + } + + /** + * 银行卡OCR + * + * @param url + * @return + */ + public BankCard bkOCR(String url) { + + String reqUrl = BK_CARD_URL.replace(BAUDU_AUTH_TOKEN_NAME, this.getAccessToken()); + String body; + try { + @Cleanup HttpResponse execute = HttpRequest.post(reqUrl) + .form("url", url) + .execute(); + body = execute.body(); + } catch (Exception e) { + log.info("OCR接口异常", e); + throw new BizException("OCR接口异常, 请联系平台管理人员"); + } + + try { + JSONObject result = initResult(body); + int cardType = result.getIntValue("bank_card_type"); + BankCardStatus.checkCardType(cardType); + String cardNo = result.getString("bank_card_number").replaceAll("\\s", ""); + String bankName = result.getString("bank_name"); + return new BankCard(bankName, cardNo); + } catch (Exception e) { + log.info("OCR识别失败", e); + throw new BizException("OCR识别失败, 请手动相关补充资料"); + } + } + + private JSONObject initResult(String body) { + if (StringUtils.isEmpty(body)) { + throw new BizException("百度OCR识别接口异常"); + } + JSONObject resObj = JSON.parseObject(body); + if (resObj.containsKey(BAUDU_ERROR_CODE)) { + throw new BizException("百度OCR识别接口异常,异常信息:" + resObj.getString(BAUDU_ERROR_DESC)); + } + JSONObject words_result = resObj.getJSONObject("words_result"); + if (words_result == null) { + JSONObject res = resObj.getJSONObject("result"); + return res; + } + return words_result; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduOCRApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduOCRApiService.java new file mode 100644 index 0000000..1263345 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/BaiduOCRApiService.java @@ -0,0 +1,95 @@ +package com.jeequan.jeepay.thirdparty.service.ocr; + +import com.jeequan.jeepay.core.interfaces.IOCRApiService; +import com.jeequan.jeepay.core.model.DBOCRConfig; +import com.jeequan.jeepay.core.model.OCRImgParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.util.OCRUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * TODO + * 百度ocr配置 + * @author crystal + * @date 2023/10/24 15:59 + */ +@Slf4j +@Service +public class BaiduOCRApiService implements IOCRApiService { + + @Autowired + private SysConfigService sysConfigService; + + private DBOCRConfig getocrConfig() { + DBOCRConfig dbocrConfig = sysConfigService.getOcrConfig(); + return dbocrConfig; + } + + @Override + public OCRImgParams getIdCardInfo(String imgUrl) { + OCRImgParams ocrImgParams = new OCRImgParams(); + BaiduClient client = createClient(); + BaiduClient.IdCard result = client.icOCR(imgUrl); + // 身份证姓名 + if (StringUtils.isNotEmpty(result.getName())) { + ocrImgParams.setIdcardName(result.getName()); + } + // 地址 + if (StringUtils.isNotEmpty(result.getAddress())) { + ocrImgParams.setIdcardAddress(result.getAddress()); + } + // 身份证号 + if (StringUtils.isNotEmpty(result.getIdNum())) { + ocrImgParams.setIdcardNo(result.getIdNum()); + } + // 有效日期 [日期格式转换] + if (StringUtils.isNotEmpty(result.getValidDate())) { + OCRUtil.setIdCardDate(result.getValidDate(), ocrImgParams); + } + return ocrImgParams; + } + + @Override + public OCRImgParams getBusinessLicenceInfo(String imgUrl) { + OCRImgParams ocrImgParams = new OCRImgParams(); + BaiduClient client = createClient(); + BaiduClient.BusinessLicence result = client.blOCR(imgUrl); + // 社会统一代码 + ocrImgParams.setLicenseNo(result.getBusNo()); + // 公司名称 + ocrImgParams.setMchFullName(result.getName()); + // 法人 + ocrImgParams.setLicensePerson(result.getPerson()); + // 地址 + ocrImgParams.setLicenseAddress(result.getAddress()); + // 经营范围 + ocrImgParams.setLicenseBusiness(result.getBusiness()); + //经营范围 + ocrImgParams.setLicenseScope(result.getBusiness()); + // 有效期 + ocrImgParams.setLicenseEffectBegin(result.getStartDate()); + ocrImgParams.setLicenseEffectEnd(result.getEndDate()); + return ocrImgParams; + } + + @Override + public OCRImgParams getBankCardInfo(String imgUrl) { + OCRImgParams ocrImgParams = new OCRImgParams(); + BaiduClient client = createClient(); + BaiduClient.BankCard result = client.bkOCR(imgUrl); + // 银行卡信息 + ocrImgParams.setSettAccountBankName(result.getBankName()); + // 卡号 + ocrImgParams.setSettAccountNo(result.getCardNo()); + return ocrImgParams; + } + + private BaiduClient createClient() { + DBOCRConfig dbocrConfig = getocrConfig(); + BaiduClient client = new BaiduClient(dbocrConfig.getBaiduApiKey(),dbocrConfig.getBaiduSecretKey()); + return client; + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/TencentOCRApiService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/TencentOCRApiService.java new file mode 100644 index 0000000..3281d95 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/ocr/TencentOCRApiService.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.thirdparty.service.ocr; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.interfaces.IOCRApiService; +import com.jeequan.jeepay.core.model.DBOCRConfig; +import com.jeequan.jeepay.core.model.OCRImgParams; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.util.OCRUtil; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.ocr.v20181119.OcrClient; +import com.tencentcloudapi.ocr.v20181119.models.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 腾讯云OCR接口 + * + * @author xiaoyu + * + * @date 2022/1/11 15:31 + */ +@Slf4j +@Service +public class TencentOCRApiService implements IOCRApiService { + + @Autowired private SysConfigService sysConfigService; + + private DBOCRConfig getocrConfig() { + DBOCRConfig dbocrConfig = sysConfigService.getOcrConfig(); + return dbocrConfig; + } + + @Override + public OCRImgParams getIdCardInfo(String imgUrl){ + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + // 创建请求对象 + IDCardOCRRequest request = new IDCardOCRRequest(); + OcrClient client = createClient(); + request.setImageUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + IDCardOCRResponse response = client.IDCardOCR(request); + log.info("【OCR识别】响应结果:{}", JSON.toJSONString(response)); + + // 身份证姓名 + if (StringUtils.isNotEmpty(response.getName())) { + ocrImgParams.setIdcardName(response.getName()); + } + // 身份证姓名 + if (StringUtils.isNotEmpty(response.getSex())) { + ocrImgParams.setIdcardSex(response.getSex()); + } + // 地址 + if (StringUtils.isNotEmpty(response.getAddress())) { + ocrImgParams.setIdcardAddress(response.getAddress()); + } + // 身份证号 + if (StringUtils.isNotEmpty(response.getIdNum())) { + ocrImgParams.setIdcardNo(response.getIdNum()); + } + // 有效日期 [日期格式转换] + if (StringUtils.isNotEmpty(response.getValidDate())) { + String validPeriod = response.getValidDate(); + OCRUtil.setIdCardDate(validPeriod, ocrImgParams); + } + + }catch (Exception e) { + log.info("【腾讯云OCR】身份证识别异常", e); + } + return ocrImgParams; + } + + @Override + public OCRImgParams getBusinessLicenceInfo(String imgUrl) { + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + // 创建请求对象 + BizLicenseOCRRequest request = new BizLicenseOCRRequest(); + OcrClient client = createClient(); + request.setImageUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + BizLicenseOCRResponse response = client.BizLicenseOCR(request); + log.info("【OCR识别】响应结果:{}", JSON.toJSONString(response)); + + // 社会统一代码 + ocrImgParams.setLicenseNo(response.getRegNum()); + // 公司名称 + ocrImgParams.setMchFullName(response.getName()); + // 法人 + ocrImgParams.setLicensePerson(response.getPerson()); + // 地址 + ocrImgParams.setLicenseAddress(response.getAddress()); + // 经营范围 + ocrImgParams.setLicenseBusiness(response.getBusiness()); + // 有效期 + OCRUtil.setLicenseDate(response.getPeriod(), ocrImgParams); + + }catch (Exception e) { + log.info("【腾讯云OCR】营业执照识别异常", e); + } + return ocrImgParams; + } + + @Override + public OCRImgParams getBankCardInfo(String imgUrl) { + OCRImgParams ocrImgParams = new OCRImgParams(); + try { + // 创建请求对象 + BankCardOCRRequest request = new BankCardOCRRequest(); + OcrClient client = createClient(); + request.setImageUrl(imgUrl); + + // 发起请求 + log.info("【OCR识别】请求的图片地址:{}", imgUrl); + BankCardOCRResponse response = client.BankCardOCR(request); + log.info("【OCR识别】响应结果:{}", JSON.toJSONString(response)); + + // 银行卡信息 + ocrImgParams.setSettAccountBankName(response.getBankInfo()); + // 卡号 + ocrImgParams.setSettAccountNo(response.getCardNo()); + + }catch (Exception e) { + log.info("【腾讯云OCR】银行卡识别异常", e); + } + return ocrImgParams; + } + + /** + * @author: xiaoyu + * @date: 2022/1/11 15:50 + * @describe: 初始化账号Client + */ + private OcrClient createClient() { + // SecretId + String secretId = getocrConfig().getTencentSecretId(); + // SecretKey + String secretKey = getocrConfig().getTencentSecretKey(); + Credential cred = new Credential(secretId, secretKey); + return new OcrClient(cred, "ap-shanghai"); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/AppPushService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/AppPushService.java new file mode 100644 index 0000000..b7953d8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/AppPushService.java @@ -0,0 +1,86 @@ +package com.jeequan.jeepay.thirdparty.service.push; + +import cn.hutool.core.util.IdUtil; +import com.getui.push.v2.sdk.ApiHelper; +import com.getui.push.v2.sdk.GtApiConfiguration; +import com.getui.push.v2.sdk.api.PushApi; +import com.getui.push.v2.sdk.common.ApiResult; +import com.getui.push.v2.sdk.dto.CommonEnum; +import com.getui.push.v2.sdk.dto.req.Audience; +import com.getui.push.v2.sdk.dto.req.Settings; +import com.getui.push.v2.sdk.dto.req.message.PushBatchDTO; +import com.getui.push.v2.sdk.dto.req.message.PushDTO; +import com.getui.push.v2.sdk.dto.req.message.PushMessage; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.push.IAppPushService; +import com.jeequan.jeepay.core.model.DBAppPushConfig; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Set; + +@Slf4j +@Service +public class AppPushService implements IAppPushService { + + /** + * 1. 第一个参数为消息内容 + * 2. 第二个参数为设备号 + */ + @Override + public Map> pushMessageToList(String content, Set cIds, DBAppPushConfig appPushConfig) { + + GtApiConfiguration apiConfig = new GtApiConfiguration(); + apiConfig.setAppId(appPushConfig.getUniPushAppId()); + apiConfig.setAppKey(appPushConfig.getUniPushAppKey()); + apiConfig.setMasterSecret(appPushConfig.getUniPushMasterSecret()); + apiConfig.setDomain(DBAppPushConfig.GT_APP_PUSH); + // 实例化ApiHelper对象,用于创建接口对象 + ApiHelper apiHelper = ApiHelper.build(apiConfig); + // 创建推送对象 + PushApi pushApi = apiHelper.creatApi(PushApi.class); + + // 根据cid进行批量单推 + PushBatchDTO pushBatchDTO = new PushBatchDTO(); + pushBatchDTO.setAsync(true); + + for (String cid : cIds) { + PushDTO pushDTO = new PushDTO<>(); + pushBatchDTO.addPushDTO(pushDTO); + + // 设置推送ID + pushDTO.setRequestId(IdUtil.fastSimpleUUID()); + + // 设置个推通道参数 + PushMessage pushMessage = new PushMessage(); + pushMessage.setNetworkType(CommonEnum.NetworkTypeEnum.TYPE_ALL.type); + pushMessage.setTransmission(content); + pushDTO.setPushMessage(pushMessage); + + // 设置接收人信息 + Audience audience = new Audience(); + pushDTO.setAudience(audience); + audience.addCid(cid); + + // 推送设置 + Settings settings = new Settings(); + settings.setTtl(-1); // 离线不发 + pushDTO.setSettings(settings); + } + + // 进行cid批量推送 + log.info("个推消息推送cids:{}", StringUtils.join(cIds, ",")); + ApiResult>> apiResult = pushApi.pushBatchByCid(pushBatchDTO); + if (apiResult.isSuccess()) { + log.info("个推消息推送成功,response:{}", apiResult.getData()); + return apiResult.getData(); + } else { + log.info("个推消息推送失败,code:{}, msg:{}", apiResult.getCode(), apiResult.getMsg()); + throw new BizException(apiResult.getMsg()); + } + } + + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/BaiduBceService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/BaiduBceService.java new file mode 100644 index 0000000..468f16b --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/push/BaiduBceService.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.thirdparty.service.push; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.push.IBaiduBceService; +import com.jeequan.jeepay.core.model.DBBaiduBceConfig; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class BaiduBceService implements IBaiduBceService { + + @Override + public String getBaiduBceToken(DBBaiduBceConfig baiduBceConfig) { + + String cacheKey = CS.BAIDU_TOKEN_CACHE_KEY + "_" + baiduBceConfig.getBaiduBceAppKey(); + String accessToken = RedisUtil.getString(cacheKey); + if (StringUtils.isNotBlank(accessToken)) { + return accessToken; + } + + String param = "grant_type=client_credentials&client_id="+ baiduBceConfig.getBaiduBceAppKey() + "&client_secret=" + baiduBceConfig.getBaiduBceAppSecret(); + log.info("百度语音请求地址 url = {}", DBBaiduBceConfig.BAIDU_OAUTH_URL + param); + try { + String responseStr = HttpUtil.post(DBBaiduBceConfig.BAIDU_OAUTH_URL + param, new HashMap<>(), 60000); + log.info("百度语音响应 response = {}", responseStr); + + if (StringUtils.isNotBlank(responseStr)) { + JSONObject obj = JSONObject.parseObject(responseStr); + + accessToken = obj.getString("access_token"); + + //保存token + RedisUtil.setString(cacheKey, accessToken, CS.BAIDU_TOKEN_TIME, TimeUnit.DAYS); + return accessToken; + } + }catch(Exception e){ + log.error("获取token失败", e); + } + return null; + } + + @Override + public void clearBaiduBceTokenCache(DBBaiduBceConfig baiduBceConfig) { + + String cacheKey = CS.BAIDU_TOKEN_CACHE_KEY + "_" + baiduBceConfig.getBaiduBceAppKey(); + String accessToken = RedisUtil.getString(cacheKey); + if (StringUtils.isNotBlank(accessToken)) { + RedisUtil.del(cacheKey); + log.info("百度token已清除,appKey={}", baiduBceConfig.getBaiduBceAppKey()); + } + } + + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxchannel/WechatChannelService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxchannel/WechatChannelService.java new file mode 100644 index 0000000..553e5c4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxchannel/WechatChannelService.java @@ -0,0 +1,160 @@ +package com.jeequan.jeepay.thirdparty.service.wxchannel; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.db.entity.MchVideoAuthEntity; +import com.jeequan.jeepay.db.entity.MchVideoCacheEntity; +import com.jeequan.jeepay.service.impl.MchVideoAuthService; +import com.jeequan.jeepay.service.impl.MchVideoCacheService; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; + +@Slf4j +@Service +public class WechatChannelService { + + private static final String DOMAIN = "http://public.hxjpayment.cn:9996"; + + private static final String CREATE_TASK = DOMAIN + "/user/create_import_task"; + + private static final String QUERY_TASK_RESULT = DOMAIN + "/user/query_import_task"; + + private static final String QUERY_VIDEO_DATA = DOMAIN + "/user/dynamic_data"; + + @Autowired + private MchVideoAuthService mchVideoAuthService; + + @Autowired + private MchVideoCacheService mchVideoCacheService; + + @Autowired + private ExecutorService executorService; + + @Autowired + private TransactionDefinition transactionDefinition; + + @Autowired + private PlatformTransactionManager transactionManager; + + public JSONObject createTask(String mchNo) { + String result = HttpUtil.get(CREATE_TASK); + JSONObject resultJson = JSON.parseObject(result); + log.info("创建任务返回参数: {}", resultJson); + int code = resultJson.getIntValue("code"); + if (code == 200) { + JSONObject bizData = resultJson.getJSONObject("data"); + MchVideoAuthEntity mchVideoAuthEntity = new MchVideoAuthEntity(); + mchVideoAuthEntity.setMchNo(mchNo); + String taskId = bizData.getString("task_id"); + mchVideoAuthEntity.setTaskId(taskId); + mchVideoAuthEntity.setUserId(taskId); + mchVideoAuthEntity.setExtra(bizData.toJSONString()); + mchVideoAuthService.save(mchVideoAuthEntity); + + return bizData; + } else { + throw new BizException("视频号请求异常"); + } + } + + public JSONObject queryTask(String taskId) { + Assert.notNull(taskId, "[taskId]不能为空"); + String result = HttpUtil.get(QUERY_TASK_RESULT + "?task_id=" + taskId); + JSONObject resultJson = JSON.parseObject(result); + int code = resultJson.getIntValue("code"); + if (code == 200) { + JSONObject bizData = resultJson.getJSONObject("data"); + MchVideoAuthEntity data = mchVideoAuthService.lambdaQuery().eq(MchVideoAuthEntity::getTaskId, taskId) + .one(); + + String status = bizData.getString("status"); + + String userId = null; + String uniqueId = null; + + if (status.equals("2")) { + userId = bizData.getString("user_id"); + uniqueId = bizData.getString("unique_id"); + data.setUserId(userId); + data.setUniqueId(uniqueId); + + // 异步请求 + executorService.execute(() -> { + videoDataColl(data); + }); + } + + data.setExtra(bizData.toJSONString()); + mchVideoAuthService.updateById(data); + + return bizData; + } else { + throw new BizException("视频号请求异常"); + } + } + + public void videoDataColl(MchVideoAuthEntity entity) { + String extra = entity.getExtra(); + JSONObject param = JSON.parseObject(extra); + String cookies = param.getString("cookies"); + + Date now = new Date(); + DateTime startTime = DateUtil.offsetMonth(now, -6); + @Cleanup HttpResponse response = HttpRequest.get(QUERY_VIDEO_DATA) + .form("cookies", cookies) + .form("user_id", entity.getUserId()) + .form("size", 30) + .form("current", 1) + .form("start_date", DateUtil.format(startTime, DatePattern.NORM_DATE_FORMATTER)) + .form("end_date", DateUtil.format(now, DatePattern.NORM_DATE_FORMATTER)) + .execute(); + + String respJsonStr = response.body(); + + JSONObject respJSON = JSON.parseObject(respJsonStr); + int code = respJSON.getIntValue("code"); + if (code != 200) { + throw new BizException("视频号获取动态数据异常"); + } + + JSONArray resultData = respJSON.getJSONObject("data").getJSONArray("records"); + + // 保存的数据 + List dataList = new ArrayList<>(); + resultData.forEach(item -> { + JSONObject jsonItem = (JSONObject) item; + MchVideoCacheEntity data = new MchVideoCacheEntity(); + data.setMchNo(entity.getMchNo()); + data.setTaskId(entity.getTaskId()); + data.setUserId(entity.getUserId()); + data.setExportId((jsonItem).getString("exportId")); + data.setUniqueId(entity.getUniqueId()); + data.setObjectId(jsonItem.getString("objectId")); + data.setExtra(jsonItem.toJSONString()); + + try { + mchVideoCacheService.save(data); + } catch (Exception ignored) { + } + }); + + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxLiteUrlLinkService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxLiteUrlLinkService.java new file mode 100644 index 0000000..5e6bb40 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxLiteUrlLinkService.java @@ -0,0 +1,209 @@ +package com.jeequan.jeepay.thirdparty.service.wxmp; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.wxmp.IWxLiteUrlLinkService; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.wx.WxAccessToken; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxMpErrorMsgEnum; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/* +* 微信支付 获取小程序 URL Link +* +* @author zx +* +* @date 2021/6/8 17:22 +*/ +@Service +@Slf4j +public class WxLiteUrlLinkService implements IWxLiteUrlLinkService { + + private static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + private static final String GENERATE_URLLINK_URL = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s"; + private static final String GENERATE_SCHEME_URL = "https://api.weixin.qq.com/wxa/generatescheme?access_token=%s"; + + // access_token过期值 + public static final List ACCESS_TOKEN_ERROR_CODES; + static { + ACCESS_TOKEN_ERROR_CODES = Arrays.asList(WxMpErrorMsgEnum.CODE_40001.getCode(), WxMpErrorMsgEnum.CODE_40014.getCode(), WxMpErrorMsgEnum.CODE_42001.getCode()); + } + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Override + public String generateSchemeLink(MchAppConfigContext mchAppConfigContext, String query, long millisecond) { + return null; + } + + @Override + public String generateUrlLink(MchAppConfigContext mchAppConfigContext, String query, long expiredTime) { + + // oauth2配置参数 + WxpayOauth2Params wxpayOauth2Params; + if(mchAppConfigContext.isIsvsubMch()){ + // 先获取 特约商户的 小程序 配置信息 + wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), mchAppConfigContext.getMchApp().getAppId(), CS.IF_CODE.WXPAY); + + // 商户未配置 || 使用服务商的小程序时 : 查询服务商的配置信息 + if(wxpayOauth2Params == null || wxpayOauth2Params.getIsUseSubmchAccount() == null || wxpayOauth2Params.getIsUseSubmchAccount() == CS.NO){ + + // 查询服务商的配置, 判断取哪个 配置条目。 + + // 查询商户 配置 的oauth2配置 ( 支付参数配置 ) selectOauth2InfoId: 配置的oauth2参数 + String ifCodeByMchPassage = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, QRCodeParams.PAGE_TYPE_WECHAT_LITE); + String selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCodeByMchPassage); + wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2ParamsByAutoSelectOauth2InfoId(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY, selectOauth2InfoId); + } + }else{ + wxpayOauth2Params = (WxpayOauth2Params)configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + } + if (wxpayOauth2Params == null || StringUtils.isBlank(wxpayOauth2Params.getLiteAppId()) || StringUtils.isBlank(wxpayOauth2Params.getLiteAppSecret())) { + throw new BizException("请配置微信oauth2小程序参数"); + } + // 获取accessToken + String accessToken = getWxLiteAccessToken(wxpayOauth2Params.getLiteAppId(), wxpayOauth2Params.getLiteAppSecret(), false); + JSONObject resJSON = getUrlLink(GENERATE_URLLINK_URL,wxpayOauth2Params, accessToken, query, expiredTime); + // access_token过期 + if (ACCESS_TOKEN_ERROR_CODES.contains(resJSON.getInteger("errcode"))) { + log.info("\n微信access_token过期,即将重新获取"); + accessToken = getWxLiteAccessToken(wxpayOauth2Params.getLiteAppId(), wxpayOauth2Params.getLiteAppSecret(), true); + // 尝试重新获取url_link + resJSON = getUrlLink(GENERATE_URLLINK_URL,wxpayOauth2Params, accessToken, query, expiredTime); + } + return resJSON.getString("url_link"); + } + + // 发起获取URL LINK请求 + private JSONObject getUrlLink(String url,WxpayOauth2Params wxpayOauth2Params, String accessToken, String query, long expiredTime) { + + JSONObject reqJSON = new JSONObject(); + if (StringUtils.isNotBlank(wxpayOauth2Params.getLitePagePath())) { + reqJSON.put("path", wxpayOauth2Params.getLitePagePath()); // 小程序路径 + } + if (StringUtils.isNotBlank(query)) { + reqJSON.put("query", query); // 进入小程序时的query + } + reqJSON.put("is_expire", true); // true-到期失效 + reqJSON.put("expire_type", 0); // 失效类型,失效时间:0,失效间隔天数:1 + reqJSON.put("expire_time", expiredTime); // 失效时间,为 Unix 时间戳 + if (StringUtils.isNotBlank(wxpayOauth2Params.getLiteEnv())) { + reqJSON.put("env_version", wxpayOauth2Params.getLiteEnv()); // 小程序版本 + } + + log.info("\n获取微信小程序URL Link,请求地址:{}", String.format(url, accessToken)); + log.info("\n获取微信小程序URL Link,请求参数:{}", reqJSON.toJSONString()); + String result = HttpUtil.createPost(String.format(url, accessToken)) + .body(reqJSON.toJSONString()) + .execute() + .body(); + log.info("\n获取微信小程序URL Link,响应:{}", result); + if (StringUtils.isBlank(result)) { + throw new BizException("获取小程序URL Link失败,返回结果为空"); + } + + JSONObject resJSON = JSONObject.parseObject(result); + if (resJSON == null || resJSON.getInteger("errcode") == null) { + throw new BizException("获取小程序URL Link失败,返回结果为空"); + } + + if (resJSON.getInteger("errcode") != 0 && !ACCESS_TOKEN_ERROR_CODES.contains(resJSON.getInteger("errcode"))) { + throw new BizException(resJSON.getString("errmsg")); + } + + return resJSON; + } + + public String getSchemeLink(WxpayOauth2Params wxpayOauth2Params, String accessToken, String query, long expiredTime) { + JSONObject reqJSON = new JSONObject(); + // true-到期失效 + reqJSON.put("is_expire", true); + // 失效类型,失效时间:0,失效间隔天数:1 + reqJSON.put("expire_type", 0); + // 失效时间,为 Unix 时间戳 + reqJSON.put("expire_time", expiredTime); + JSONObject jump_wxa = new JSONObject(); + jump_wxa.put("path",wxpayOauth2Params.getLitePagePath()); + jump_wxa.put("query",query); +// jump_wxa.put("env_version", "trial"); + // 小程序版本 + if (StringUtils.isNotBlank(wxpayOauth2Params.getLiteEnv())) { + jump_wxa.put("env_version", wxpayOauth2Params.getLiteEnv()); + } + reqJSON.put("jump_wxa",jump_wxa); + log.info("\n获取微信小程序URL Scheme,请求地址:{}", String.format(GENERATE_SCHEME_URL, accessToken)); + log.info("\n获取微信小程序URL Scheme,请求参数:{}", reqJSON.toJSONString()); + String result = HttpUtil.createPost(String.format(GENERATE_SCHEME_URL, accessToken)) + .body(reqJSON.toJSONString()) + .execute() + .body(); + log.info("\n获取微信小程序URL Scheme,响应:{}", result); + if (StringUtils.isBlank(result)) { + throw new BizException("获取小程序URL Scheme失败,返回结果为空"); + } + JSONObject resJSON = JSONObject.parseObject(result); + if (resJSON == null || resJSON.getInteger("errcode") == null) { + throw new BizException("获取小程序URL Scheme失败,返回结果为空"); + } + + if (resJSON.getInteger("errcode") != 0 && !ACCESS_TOKEN_ERROR_CODES.contains(resJSON.getInteger("errcode"))) { + throw new BizException(resJSON.getString("errmsg")); + } + return resJSON.getString("openlink"); + } + + /** + * 获取access_token,不要随便刷新token + * 当接口返回过期时,才需要刷新token + * @param isRefreshAccessToken true-刷新token + * */ + private String getWxLiteAccessToken(String appId, String appSecret, boolean isRefreshAccessToken) { + + // 刷新access_token + if (isRefreshAccessToken) { + RedisUtil.del(appId); + } + + String accessToken = RedisUtil.getString(appId); + if (StringUtils.isNotBlank(accessToken)) { + return accessToken; + } + + // 获取accessToken + String url = String.format(GET_ACCESS_TOKEN_URL, appId, appSecret); + log.info("\n获取微信access_token,请求:{}", url); + String res = HttpUtil.get(url); + log.info("\n获取微信access_token,响应:{}", res); + if (StringUtils.isBlank(res)) { + throw new BizException("获取accessToken失败"); + } + + WxAccessToken wxAccessToken = JSON.parseObject(res, WxAccessToken.class); + if (wxAccessToken == null || StringUtils.isBlank(wxAccessToken.getAccessToken()) || wxAccessToken.getExpiresIn() == null) { + throw new BizException("获取accessToken失败"); + } + + if (wxAccessToken.getExpiresIn() - 100 > 0) { + RedisUtil.setString(appId, wxAccessToken.getAccessToken(), wxAccessToken.getExpiresIn() - 100, TimeUnit.SECONDS); + }else { + RedisUtil.setString(appId, wxAccessToken.getAccessToken(), wxAccessToken.getExpiresIn(), TimeUnit.SECONDS); + } + return wxAccessToken.getAccessToken(); + } + + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxMpTemplateMsgService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxMpTemplateMsgService.java new file mode 100644 index 0000000..63526d8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxMpTemplateMsgService.java @@ -0,0 +1,169 @@ +package com.jeequan.jeepay.thirdparty.service.wxmp; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchWxmpUser; +import com.jeequan.jeepay.core.interfaces.wxmp.IWxMpTemplateMsgService; +import com.jeequan.jeepay.core.model.DBWxMpConfig; +import com.jeequan.jeepay.core.model.wx.wxmp.WxUserInfo; +import com.jeequan.jeepay.model.CacheInfo; +import com.jeequan.jeepay.service.mapper.CacheTkMapper; +import com.jeequan.jeepay.thirdparty.model.WxmpServerContext; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.bean.WxOAuth2UserInfo; +import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.service.WxOAuth2Service; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpOAuth2ServiceImpl; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 微信公众号授权回调 code -> openid 实现类 + * + * @author terrfly + * + * @date 2021/6/8 17:22 + */ +@Service +@Slf4j +@AllArgsConstructor +public class WxMpTemplateMsgService implements IWxMpTemplateMsgService { + + @Autowired + private WxmpServerContext wxmpServerContext; + @Autowired + private CacheTkMapper cacheTkMapper; + + @Override + public WxUserInfo code2WxUserInfo(String code, DBWxMpConfig wxMpConfig) { + + try { + WxMpService wxMpService = wxmpServerContext.getWxService(wxMpConfig); + + WxOAuth2Service wxOAuth2Service = new WxMpOAuth2ServiceImpl(wxMpService); + WxOAuth2AccessToken accessToken = wxOAuth2Service.getAccessToken(code); + + WxOAuth2UserInfo wxOAuth2UserInfo = wxOAuth2Service.getUserInfo(accessToken, "zh_CN"); + + WxUserInfo wxUserInfo = new WxUserInfo(); + BeanUtil.copyProperties(wxOAuth2UserInfo, wxUserInfo); + + return wxUserInfo; + } catch (WxErrorException e) { + log.error("获取微信授权信息失败", e); + } + + return null; + } + + @Override + public void sendTemplateMessage(List userList, String templateMessage, DBWxMpConfig wxMpConfig,String templateId) { + + // 构造模板消息 + WxMpTemplateMessage wxMpTemplateMessage = new WxMpTemplateMessage(); + wxMpTemplateMessage.setTemplateId(templateId); //模板ID + + List dataList = JSON.parseArray(templateMessage, WxMpTemplateData.class); + wxMpTemplateMessage.setData(dataList); // 模板内容 + + WxMpService wxService = wxmpServerContext.getWxService(wxMpConfig); + + Set openIdSet = userList.stream().map(MchWxmpUser::getWxOpenId).collect(Collectors.toSet()); + + for (String openId : openIdSet) { + + try { + wxMpTemplateMessage.setToUser(openId); + + wxService.getTemplateMsgService().sendTemplateMsg(wxMpTemplateMessage); + + log.info("微信公众号消息获取access_token={}", RedisUtil.getString(CS.CACHE_KEY_WX_JAVA+":access_token:"+wxMpConfig.getWxAppId())); + + log.info("微信公众号消息发送成功,toOpenId={}, templateMessage={}", openId, templateMessage); + }catch (Exception e) { + log.error("微信公众号消息发送失败:{}", e.getMessage(), e); + } + } + } + + + /** + * 发送消息扩展方法 + * @param userList + * @param templateMessage + * @param wxMpConfig + */ +// @Override +// public void sendTemplateMessageExtend(List userList, String templateMessage, DBWxMpConfig wxMpConfig) { +// String accessToken = getExtAccessToken(wxMpConfig); +// if(StringUtils.isEmpty(accessToken)){ +// sendTemplateMessage(userList,templateMessage,wxMpConfig,null); +// }else{ +// String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken; +// // 构造模板消息 +// String templateId = wxMpConfig.getPaySuccMsgTemplateId(); +// List dataList = JSON.parseArray(templateMessage, JSONObject.class); +// Set openIdSet = userList.stream().map(MchWxmpUser::getWxOpenId).collect(Collectors.toSet()); +// JSONObject params = new JSONObject(); +// JSONObject data = new JSONObject(); +// for (JSONObject item:dataList) { +// data.put(item.getString("name"),item); +// } +// params.put("template_id",templateId); +// params.put("data",data); +// for (String openId : openIdSet) { +// try { +// params.put("touser",openId); +// log.info("微信模板请求参数:{}",JSON.toJSONString(params)); +// HttpResponse response = HttpRequest.post(url).body(params.toString()).execute(); +// if(!response.isOk()){ +// log.info("消息发送失败"); +// continue; +// } +// log.info("微信模板消息接口返回参数:{}",response.body()); +// JSONObject respBody = JSON.parseObject(response.body()); +// if(respBody.getInteger("errcode") != null && respBody.getInteger("errcode") != 0){ +// log.info("微信模板消息发送失败:{}",respBody.getString("errmsg")); +// continue; +// } +// }catch (Exception e) { +// log.error("微信公众号消息发送失败:{}", e.getMessage(), e); +// } +// } +// } +// } + + /** + * 扩展方法获取accessToken + * @param wxMpConfig + * @return + */ + private String getExtAccessToken(DBWxMpConfig wxMpConfig) { + String keyCode = "accesstoken:" + wxMpConfig.getWxAppId(); + try { + CacheInfo cacheInfo = cacheTkMapper.getKeyCode(keyCode); + if(cacheInfo == null){ + return null; + } + return cacheInfo.getAccessToken(); + }catch (Exception e){ + return null; + } + } +} + diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxTgAppletService.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxTgAppletService.java new file mode 100644 index 0000000..803ec7a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/wxmp/WxTgAppletService.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.thirdparty.service.wxmp; + +import cn.hutool.core.util.URLUtil; +import cn.hutool.http.HttpStatus; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.AccessMsgException; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.AppletResult; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.core.model.QRCodeParams; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.openapi.AccessError; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.db.entity.PayOrder; +import com.jeequan.jeepay.service.impl.SysConfigService; +import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * TODO + * 微信托管相关业务处理 + * @author crystal + * @date 2023/11/29 11:08 + */ +@Service +public class WxTgAppletService { + + public final static String THIRD_ACCESS_TOEN = "authAccessToken"; + + public final static String THIRD_COMPONENT_TOKEN = "componentToken"; + + public final static String TG_API_DOMAIN = "https://xcx.shouyinbei.cn/prod-mini-api"; + + @Autowired private ConfigContextQueryService configContextQueryService; + + @Autowired private WxLiteUrlLinkService wxLiteUrlLinkService; + + + /** + * 获取托管小程序支付参数 + * @param mchAppConfigContext + * @return + */ + public AppletResult toAppletPayment(PayOrder payOrder, MchAppConfigContext mchAppConfigContext,QRCodeParams qrCodeParams) { + WxpayOauth2Params wxpayOauth2Params; + if(mchAppConfigContext.isIsvsubMch()){ + // 先获取 特约商户的 小程序 配置信息 + wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchApplyment().getIsvNo(), mchAppConfigContext.getMchApp().getAppId(), CS.IF_CODE.WXPAY); + // 商户未配置 || 使用服务商的小程序时 : 查询服务商的配置信息 + if(wxpayOauth2Params == null || wxpayOauth2Params.getIsUseSubmchAccount() == null || wxpayOauth2Params.getIsUseSubmchAccount() == CS.NO){ + // 查询服务商的配置, 判断取哪个 配置条目。 + // 查询商户 配置 的oauth2配置 ( 支付参数配置 ) selectOauth2InfoId: 配置的oauth2参数 + String ifCodeByMchPassage = configContextQueryService.queryIfCodeByPageType(mchAppConfigContext, QRCodeParams.PAGE_TYPE_WECHAT_LITE); + String selectOauth2InfoId = configContextQueryService.queryAgentOrIsvSelectOauth2InfoId(mchAppConfigContext.getMchApplyment(), ifCodeByMchPassage); + wxpayOauth2Params = (WxpayOauth2Params) configContextQueryService.queryIsvOauth2ParamsByAutoSelectOauth2InfoId(mchAppConfigContext.getMchApplyment().getIsvNo(), CS.IF_CODE.WXPAY, selectOauth2InfoId); + } + }else{ + wxpayOauth2Params = (WxpayOauth2Params)configContextQueryService.queryNormalOauth2Params(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), CS.IF_CODE.WXPAY); + } + if (wxpayOauth2Params == null || StringUtils.isBlank(wxpayOauth2Params.getLiteAppId()) || StringUtils.isBlank(wxpayOauth2Params.getLiteAppSecret())) { + throw new BizException("请配置微信oauth2小程序参数"); + } + String accessToken = getThirdAccessToken(wxpayOauth2Params.getLiteAppId()); + String query = JeepayKit.TOKEN_KEY +"=" + qrCodeParams.getTk() + "&order_no="+payOrder.getPayOrderId() + "&price=" + AmountUtil.convertCent2Dollar(payOrder.getFindAmt()) + "&env=h5"; + wxpayOauth2Params.setLitePagePath("pages/payment/index"); + String schemeLink = wxLiteUrlLinkService.getSchemeLink(wxpayOauth2Params, accessToken, query, payOrder.getExpiredTime().getTime()); + AppletResult result = new AppletResult(wxpayOauth2Params,schemeLink,query); + result.setStatus(payOrder.getState()); + return result; + } + + public String getComponentToken(String appid) { + return getAccessToken(appid,THIRD_COMPONENT_TOKEN); + } + + public String getThirdAccessToken(String appid) { + String accessToken = getAccessToken(appid, THIRD_ACCESS_TOEN); + if(StringUtils.isEmpty(accessToken)){ + throw new AccessMsgException(AccessError.dataError("当前微信APPID["+appid+"]参数未授权到系统")); + } + return accessToken; + } + + public String getAccessToken(String appid,String tokenName) { + String url = TG_API_DOMAIN + "/api/open/cache/get?appid="+appid; + String response = HttpUtil.get(url); + if(StringUtils.isEmpty(response)){ + throw new BizException("接口异常"); + } + JSONObject respData = JSON.parseObject(response); + int code = respData.getIntValue("code"); + if(code != HttpStatus.HTTP_OK){ + throw new BizException(respData.getString("msg")); + } + JSONObject bizData = respData.getJSONObject("data"); + return bizData.getString(tokenName); + } +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/NotifyMsgRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/NotifyMsgRequest.java new file mode 100644 index 0000000..4126c19 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/NotifyMsgRequest.java @@ -0,0 +1,49 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version NotifyMsgRequest.java, v 0.1 2023-02-20 10:29 yangjun + */ +@Data +public class NotifyMsgRequest { + + /** + * 消息唯一ID,推荐使用UUID + */ + private String index; + + /** + * 设备SN + */ + private String sn; + + /** + * 服务商的 token, 预先通过安全渠道分配,使得服务商对该 SN 有操作权限 + */ + private String token; + + /** + * 通知消息内容,长度最长128个字节 + */ + private String message; + + /** + * 交易单号/商户单号/交易流水号 + */ + private String trace_no; + + /** + * 指音量设置值,范围为 0 到 100 60 + */ + private String vol; + + /** + * tts语速,速度范围为0-100,默认为65 + */ + private String speed; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PayMsgRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PayMsgRequest.java new file mode 100644 index 0000000..9f2fb30 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PayMsgRequest.java @@ -0,0 +1,82 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version PayMsgRequest.java, v 0.1 2023-02-20 10:28 yangjun + */ +@Data +public class PayMsgRequest { + + /** + * 消息唯一ID,推荐使用UUID + */ + private String index; + + /** + * 设备SN + */ + private String sn; + + /** + * 支付金额,单位为分,范围为 1 至 2147483647 + */ + private String price; + + /** + * 支付类型 [0,255]的整形值 + * 0 prefix + * 1 支付宝 + * 2 微信支付 + * 3 云支付 + * 4 余额支付 + * 5 微信储值 + * 6 微信买单 + * 7 银联刷卡 + * 8 会员卡消费 + * 9 会员卡充值 + * 10 翼支付 + * 11 退款 + * 12 支付宝退款 + * 13 微信退款 + * 14 银行卡退款 + * 15 银联退款 + * 16 工行e支付 + * 17 长沙银行到账 + * 18 QQ钱包到账 + * 19 京东支付 + * 20 用户取消支付 + * 21 西安银行到账 + * 22 西银惠支付 + * 23 微邮付 + * 24 云收单收款 + * 25 云闪付收款 + * 28 数字人民币到账 + */ + private Integer pt; + + /** + * 服务商的 token, 预先通过安全渠道分配,使得服务商对该 SN 有操作权限 + */ + private String token; + + /** + * 交易单号/商户单号/交易流水号 + */ + private String trace_no; + + /** + * 指音量设置值,范围为 0 到 100 60 + */ + private Integer vol; + + /** + * 是否播放自定义收款后缀, + * 1 表示开启 0-表示关闭 + */ + private Integer addition; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintContextRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintContextRequest.java new file mode 100644 index 0000000..f3fc2b1 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintContextRequest.java @@ -0,0 +1,48 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +import java.util.List; + +/** + * @author yangjun + * @version PrintContextRequest.java, v 0.1 2023-02-20 13:50 yangjun + */ +@Data +public class PrintContextRequest { + + /** + * 音箱播报内容 + */ + private String sc; + + /** + * 打印内容 + */ + private List pd; + + /** + * 打印机打印联数 + * 如果为空,默认打印一联 + */ + private String cn; + + /** + * 是否标签打印 + * 0-否 1-是。空则默认为 0 + */ + private String lable; + + /** + * 小票打印logo时的默认logo名称 + */ + private String logo; + + /** + * 打印完成后进纸行数,不填的话默认为3 + */ + private String feed_num; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintPdRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintPdRequest.java new file mode 100644 index 0000000..35ade5d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintPdRequest.java @@ -0,0 +1,80 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version PrintPdRequest.java, v 0.1 2023-02-20 15:03 yangjun + */ +@Data +public class PrintPdRequest { + + /** + * 行数据类型: + * 0- base64 编码的logo + * 数据; + * 1- 交易或通知数据; + * 2- 二维码数据; + * 3- 空行; + * 4- 分割横线; + * 5- 广告数据 + * 6- 一维条码数据 + * 7- logo文件名称 + *

+ * 备注:打印的一维条码为CODE128,可以打印的数据格式为 + * 1、数字 + * 2、字符+数字 + */ + private String tp; + + /** + * 数据内容 + */ + private String cv; + + /** + * 对齐方式,默认左对齐 + * 0- 左对齐 + * 1- 居中 + * 2- 右对齐 + */ + private String al; + + /** + * 行间距,单位点 + */ + private String ls; + + /** + * 字间距 + */ + private String ws; + + /** + * 1-小字体 + * 2-中字体 + * 3-大字体 + *

+ * 默认值为1 + * 小字体:24*24 + * 中字体:36*36 + * 大字体:48*48 + */ + private String fs; + + /** + * 是否增加下划线, + * 0-否 1-是。空则为 0-否 + */ + private String tu; + + /** + * 是否加粗,0-否 + * 1-是。空则为 0-否 + */ + private String tb; + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintRequest.java new file mode 100644 index 0000000..6388813 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/PrintRequest.java @@ -0,0 +1,42 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * 云打印+语音播报 + * + * @author yangjun + * @version PrintRequest.java, v 0.1 2023-02-20 13:49 yangjun + */ +@Data +public class PrintRequest { + + /** + * 消息唯一ID,推荐使用UUID + */ + private String index; + + /** + * 设备SN + */ + private String sn; + + /** + * 服务商的 token, 预先通过安全渠道分配,使得服务商对该 SN 有操作权限 + */ + private String token; + + /** + * 交易单号/商户单号/交易流水号 + */ + private String trace_no; + + /** + * 消息内容 + */ + private PrintContextRequest context; + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/UpdatePayParamRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/UpdatePayParamRequest.java new file mode 100644 index 0000000..0583b60 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/UpdatePayParamRequest.java @@ -0,0 +1,177 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version UpdatePayParamRequest.java, v 0.1 2023-02-20 14:01 yangjun + */ +@Data +public class UpdatePayParamRequest { + + + /** + * 消息唯一ID,推荐使用UUID + */ + private String index; + + /** + * 设备SN + */ + private String sn; + + /** + * 服务商的 token, 预先通过安全渠道分配,使得服务商对该 SN 有操作权限 + */ + private String token; + + /** + * 商户号 + */ + private String shopid; + + /** + * 终端号 + */ + private String termid; + + /** + * 是否截获收银小票金额 + * 0-关闭 1-开启 + */ + private Integer bill_cap; + + /** + * 是否上送收银小票内容 + * 0-关闭 1-开启 + */ + private Integer bill_upload; + + /** + * 支付超时时间,单位:秒 + * 超时退出支付并打印收银小票 + */ + private Integer bill_timeout; + + /** + * 收银小票打印标志 + * 0-不打印 + * 1-支付前打印 + * 2-支付后打印 默认值 + */ + private Integer bill_print; + + /** + * 支付平台支付回调接口URL + * 与3.3中支付平台提供的url相同,接收云打印上送的交易数据和小票内容 + */ + private String url; + + /** + * 支付平台交易查询回调接口URL + * 与3.5中支付平台提供的url相同,接收云打印上送的交易id + */ + private String url_query; + + /** + * 交易结果查询时间间隔,单位:秒 + */ + private Integer query_interval; + + /** + * 最大交易结果查询次数 + */ + private Integer query_num; + + /** + * 收银小票金额截取关键字,每个关键字直接用逗号分隔,不能带空格 + */ + private String keyword_cap; + + /** + * 强制打印关键字,每个关键字直接用逗号分隔,不能带空格 + */ + private String keyword_skip; + + /** + * 收银单号前缀 + */ + private String order_prefix; + + /** + * 重复的订单编号,是否跳过 true/false + */ + private Boolean order_skip; + + /** + * 预配置时,收银小票金额拦截关键字,只允许一个关键字 + */ + private String preset_prefix; + + /** + * 收银系统预配置数据 + * 支付预配置的收银系统,可以通过3.7 接口获取 + */ + private String preset_data; + + /** + * 预配置参数时间戳 + * 可以通过3.7 接口获取 + */ + private String preset_timestamp; + + /** + * 16字节唯一验证码 + * 从开机时打印的参数配置码中提取 + * 参数配置码格式:sn,authcode + */ + private String authcode; + + /** + * 支付错误信息打印标志 + * 支付失败时是否打印错误信息 + * true-打印 + * false-不打印 默认值 + */ + private Boolean errinfo_print; + + /** + * 退款码打印标志 + * 支付成功小票中是否打印退款码 + * true-打印 默认值 + * false-不打印 + */ + private Boolean refundcode_print; + + /** + * 支付模式 + * 1-被扫 默认值 + * 2-主扫 + */ + private Integer pay_mode; + + /** + * 主扫时生成的支付二维码数据前缀,在后面会拼接上shopid,termid,amount,uuid + * 客户扫码支付成功后,支付平台通过3.5接口通知交易结果 + */ + private String qr_prefix; + + /** + * 32字节md5签名密钥 + */ + private String md5key; + + /** + * 是否打印支付小票 + * 0-否 1-是 + */ + private Integer bill_pay_print; + + + private String vid; + + private String pid; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayNotifyRequest.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayNotifyRequest.java new file mode 100644 index 0000000..9fba14c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayNotifyRequest.java @@ -0,0 +1,48 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version ZwPayNotifyRequest.java, v 0.1 2023-02-20 14:41 yangjun + */ +@Data +public class ZwPayNotifyRequest { + + /** + * 交易结果 + * 0-交易成功 + * 1-交易失败 + * 2-正在交易 + */ + private String code; + + /** + * 错误信息 + */ + private String message; + + /** + * 云音箱/云打印sn + */ + private String sn; + + /** + * 服务商的 token, 预先通过安全渠道分配,使得服务商对该sn 有操作权限 + */ + private String token; + + /** + * 唯一交易序号 + * 必须与请求交易的uuid相同 + */ + private String uuid; + + /** + * 支付小票打印内容,内容与3.1.2中的pd报文结构一致 + */ + private String bill; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayParam.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayParam.java new file mode 100644 index 0000000..f1e6f8e --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayParam.java @@ -0,0 +1,57 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * 智网支付参数 + * + * @author yangjun + * @version ZwPayResponse.java, v 0.1 2023-02-20 14:27 yangjun + */ +@Data +public class ZwPayParam { + + /** + * 云音箱/云打印sn + */ + private String sn; + + /** + * 商户号 + */ + private String shopid; + + /** + * 终端号 + */ + private String termid; + + /** + * 支付码 + */ + private String paycode; + + /** + * 交易金额、以元为单位 + */ + private String amount; + + /** + * 唯一交易序号 + */ + private String uuid; + + /** + * 收银小票数据 + * 3.2中bill_upload = 1时上送 + */ + private String bill_data; + + /** + * md5签名 + */ + private String md5; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayQueryParam.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayQueryParam.java new file mode 100644 index 0000000..26e50de --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/request/ZwPayQueryParam.java @@ -0,0 +1,39 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.request; + +import lombok.Data; + +/** + * @author yangjun + * @version ZwPayQueryParam.java, v 0.1 2023-02-20 14:33 yangjun + */ +@Data +public class ZwPayQueryParam { + + /** + * 云音箱/云打印sn + */ + private String sn; + + /** + * 商户号 + */ + private String shopid; + + /** + * 终端号-门店号 + */ + private String termid; + + /** + * 唯一交易号 + */ + private String uuid; + + /** + * md5签名 + */ + private String md5; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/BaseResponse.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/BaseResponse.java new file mode 100644 index 0000000..88184c8 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/BaseResponse.java @@ -0,0 +1,48 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.response; + +import lombok.Data; + +/** + * @author yangjun + * @version BaseReponse.java, v 0.1 2023-02-20 10:24 yangjun + */ +@Data +public class BaseResponse { + + /** + * 返回码 + */ + private String respCode; + + /** + * 返回消息 + */ + private String respMsg; + + /** + * 返回数据 + */ + private Object respData; + + + /** + * 返回码 + */ + private String errcode; + + /** + * 返回信息 + */ + private String errmsg; + + public Boolean isSuccess() { + if ("0".equals(this.errcode)) { + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayQueryResult.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayQueryResult.java new file mode 100644 index 0000000..4686091 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayQueryResult.java @@ -0,0 +1,43 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.response; + +import lombok.Data; + +/** + * @author yangjun + * @version ZwPayQueryResult.java, v 0.1 2023-02-20 14:34 yangjun + */ +@Data +public class ZwPayQueryResult { + + /** + * 交易结果 + * 0-交易成功 + * 1-交易失败 + * 2-正在交易 + */ + private String code; + + /** + * 错误信息 + */ + private String message; + + /** + * 云音箱/云打印sn + */ + private String sn; + + /** + * 唯一交易序号 + * 必须与请求交易的uuid相同 + */ + private String uuid; + + /** + * 支付小票打印内容,内容与3.1.2中的pd报文结构一致 + */ + private String bill; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayResult.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayResult.java new file mode 100644 index 0000000..ff3c4ca --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/model/response/ZwPayResult.java @@ -0,0 +1,39 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.model.response; + +import lombok.Data; + +/** + * @author yangjun + * @version ZwPayResult.java, v 0.1 2023-02-20 14:34 yangjun + */ +@Data +public class ZwPayResult { + + /** + * 交易结果 + * 0-交易成功 + * 1-交易失败 + * 2-正在交易 + */ + private String code; + + /** + * 错误信息 + */ + private String message; + + /** + * 唯一交易序号 + * 必须与请求交易的uuid相同 + */ + private String uuid; + + /** + * 支付小票打印内容,内容与3.1.2中的pd报文结构一致 + */ + private String bill; + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SignatureUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SignatureUtil.java new file mode 100644 index 0000000..22abada --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SignatureUtil.java @@ -0,0 +1,312 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.uils; + +import com.alibaba.fastjson.JSONObject; +import com.clj.leshuapay.sdk.exception.LeshuaException; +import com.clj.leshuapay.sdk.util.LeshuaSignature; +import com.clj.leshuapay.sdk.util.SignUtil; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author yangjun + * @version SignatureUtil.java, v 0.1 2023-02-20 14:47 yangjun + */ +@Slf4j +public class SignatureUtil { + + private static final String SECRET_KEY = "key"; + + private static Pattern UNDERLINE_PATTERN = Pattern.compile("[A-Z]"); + + /** + * 将对象转换成map,key为属性名,value为属性值,值为null的属性排除 + * + * @param obj + * @return + */ + public static Map toMap(Object obj) { + Map map = new ConcurrentSkipListMap<>(); + Field[] fields = obj.getClass().getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + Object val = field.get(obj); + if (val != null) { + String key = field.getName(); + map.put(camelToUnderline(key), String.valueOf(val)); + } + } catch (IllegalArgumentException | IllegalAccessException e) { + log.error(e.getMessage(), e); + } + } + return map; + } + + + /** + * 驼峰转下划线 + */ + public static String camelToUnderline(String str) { + Matcher matcher = UNDERLINE_PATTERN.matcher(str); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); + } + matcher.appendTail(sb); + return sb.toString(); + } + + + /** + * 计算签名 + * + * @param paramMap + * @param key + * @return + */ + public static String getMD5Sign(Map paramMap, String key) { + if (paramMap == null || paramMap.isEmpty()) { + log.warn("待签名参数map为空!"); + return null; + } + paramMap.remove("md5"); + String result = JeepayKit.getSign(paramMap, key); + return result; + } + + /** + * 计算签名 + * + * @param paramMap + * @param exludedSignParams 计算签名排除的参数 + * @param key + * @return + */ + public static String generateMd5Sign(Map paramMap, Set exludedSignParams, String key) { + if (paramMap == null || paramMap.isEmpty()) { + log.warn("待签名参数map为空!"); + return null; + } + String str2Sign = generateMd5SignStr(paramMap, exludedSignParams, key); + String result = DigestUtils.md5Hex(str2Sign).toUpperCase(); + log.info("MD5签名原始串:{},签名结果:{}", new Object[]{str2Sign, result}); + return result; + } + + /** + * 从API返回的XML数据里面重新计算一次签名 + * + * @param responseString + * @param exludedSignParams + * @param key + * @return + * @throws DocumentException + */ + public static String getSignFromResponseString(String responseString, Set exludedSignParams, String key) throws DocumentException { + Map map = getMapFromXML(responseString); + //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较 + return LeshuaSignature.getMD5Sign(map, exludedSignParams, key); + } + + public static void main(String[] args) throws DocumentException { + String jsonStr = "{\"bill_data\":\" 财来聚美食城收银小票\\n收银员:店长(1001)\\n消费流水:202302241642010040060\\n牌号:0060\\n打印时间:2023-02-24 16:42:01\\n--------------------------------\\n商品名称 单价 数量 小计\\n无码商品\\n 1 0.1\\n--------------------------------\\n总计:0.1 支付方式:现金:0.1\\n应收:0.1\\n实收:0.1 找零:0.0\\n\",\"uuid\":\"10482023022416422904\",\"sn\":\"CP1502210080002\",\"paycode\":\"288193019487752692\",\"shopid\":\"M1663659251\",\"termid\":\"1048\",\"md5\":\"6C0395EDF01C5392E2E4B42C2992ED3B\",\"amount\":\"0.10\"}"; + + String jsonStr2 = "{\"bill_data\":\" 财来聚美食城收银小票\\n收银员:店长(1001)\\n消费流水:202302271205537060002\\n牌号:0002\\n打印时间:2023-02-27 12:05:54\\n--------------------------------\\n商品名称 单价 数量 小计\\n无码商品\\n 1 0.02\\n--------------------------------\\n总计:0.02 支付方式:现金:0.02\\n应收:0.02\\n实收:0.02 找零:0.00\\n\",\"uuid\":\"10482023022712060406\",\"sn\":\"CP1502210080002\",\"paycode\":\"130300082400702149\",\"shopid\":\"M1663659251\",\"termid\":\"1048\",\"md5\":\"E6B0249A3C95F4CCF6BE255C624FF7EB\",\"amount\":\"0.02\"}"; + + boolean abc = checkIsSignValidFromResponseString(jsonStr2, "B5BB463ADA7B68B1005CC25D2E5BEDC7"); + log.info("========>" + abc); + } + + + /** + * 检查api返回数据的签名 + * + * @param responseString + * @param key + * @return + * @throws DocumentException + */ + public static boolean checkIsSignValidFromResponseString(String responseString, String key) { + Map map = JSONObject.parseObject(responseString, Map.class); + + String sign = map.get("md5").toString(); + if (StringUtils.isEmpty(sign)) { + log.error("API返回的数据签名数据不存在"); + return false; + } + log.debug("服务器回包里面的签名是:{}", sign); + // 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较 + String verSign = getMD5Sign(map, key); + + if (!sign.equalsIgnoreCase(verSign)) { + // 签名验不过,表示这个API返回的数据有可能已经被篡改了 + log.error("API返回的数据签名验证不通过,verSign={},sign={}", verSign, sign); + return false; + } + return true; + } + + /** + * 拼接用于签名的参数 + * + * @param paramMap + * @param md5Key + * @return + */ + private static String buildParam4Sign(Map paramMap, String md5Key) { + Set keySet = paramMap.keySet(); + StringBuilder param = new StringBuilder(20 * keySet.size()); + String[] keys = keySet.toArray(new String[keySet.size()]); + Arrays.sort(keys); + for (String key : keys) { +// if (exludedSignParams != null && exludedSignParams.contains(key)) { +// continue; +// } + Object value = paramMap.get(key); + // 排除值为null的情况 + if (value != null) { + param.append(key).append("=").append(value).append("&"); + } + } + param.append("key").append("=").append(md5Key); + return param.toString(); + } + + /** + * 拼接用于签名的参数 + * + * @param paramMap + * @param exludedSignParams + * @param md5Key + * @return + */ + private static String generateMd5SignStr(Map paramMap, Set exludedSignParams, String md5Key) { + Set keySet = paramMap.keySet(); + StringBuilder param = new StringBuilder(20 * keySet.size()); + String[] keys = keySet.toArray(new String[keySet.size()]); + Arrays.sort(keys); + for (String key : keys) { + if (exludedSignParams != null && exludedSignParams.contains(key)) { + continue; + } + Object value = paramMap.get(key); + // 排除值为null的情况 + if (value != null) { + param.append(key).append("=").append(value).append("&"); + } + } + param.append(SECRET_KEY).append("=").append(md5Key); + return param.toString(); + } + + /** + * 将XML字符串转换成map + * + * @param xmlString + * @return + * @throws DocumentException + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public static Map getMapFromXML(String xmlString) throws DocumentException { + // 这里用dom的方式解析回包的最主要目的是防止API新增回包字段 + org.dom4j.Document document = DocumentHelper.parseText(xmlString); + Element root = document.getRootElement(); + List eleList = root.elements(); + if (eleList != null) { + Map map = new HashMap(eleList.size()); + for (Object obj : eleList) { + if (!(obj instanceof Element)) { + log.warn("节点[{}]不是Element,忽略!", obj); + continue; + } + Element ele = (Element) obj; + map.put(ele.getName(), ele.getText()); + } + return map; + } + return Collections.emptyMap(); + + } + + + /** + * 计算base64签名,用于商户进件等 + * + * @param agentKey + * @param data + * @return + * @throws UnsupportedEncodingException + */ + public static String getBase64Sign(String agentKey, JSONObject data) throws UnsupportedEncodingException { + StringBuilder sb = new StringBuilder(); + sb.append(SignUtil.SING_PREFIX).append(agentKey).append(data); + return Base64.encodeBase64String(DigestUtils.md5Hex(sb.toString()).getBytes(SignUtil.DEFAULT_CHARSET)); + } + + public static String getRiskBase64Sign(String agentKey, String data) throws LeshuaException { + StringBuilder sb = new StringBuilder(); + sb.append(SignUtil.SING_PREFIX).append(agentKey).append(data); + try { + return Base64.encodeBase64String(DigestUtils.md5Hex(sb.toString()).toLowerCase().getBytes(SignUtil.DEFAULT_CHARSET)); + } catch (Exception e) { + throw new LeshuaException("签名获取失败", e); + } + } + + public static Set reqExcludedSignParams() { + Set excludedSignParams = new HashSet(1); + excludedSignParams.add("md5"); + return excludedSignParams; + } + + /** + * 响应结果不参与计算签名的参数 + * + * @return + */ + public static Set resExcludedSignParams() { + Set excludedSignParams = new HashSet<>(2); + excludedSignParams.add("sign"); + excludedSignParams.add("resp_code"); + return excludedSignParams; + } + + + /** + * 响应结果不参与计算签名的参数 + * + * @return + */ + public static Set notifyExcludedSignParams() { + Set excludedSignParams = new HashSet<>(2); + excludedSignParams.add("sign"); + excludedSignParams.add("error_code"); + return excludedSignParams; + } + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SmartLinkUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SmartLinkUtil.java new file mode 100644 index 0000000..c41c511 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/SmartLinkUtil.java @@ -0,0 +1,158 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.uils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.device.PayOrderInfo4Device; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.DateKit; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.thirdparty.service.zw.model.request.*; +import com.jeequan.jeepay.thirdparty.service.zw.model.response.BaseResponse; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author yangjun + * @version SmartLinkAllServiceImpl.java, v 0.1 2023-02-20 10:07 yangjun + */ +@Service +@Slf4j +@AllArgsConstructor +public class SmartLinkUtil { + /** + * 请求智网接口 + * + * @param url + * @param param + * @param resultClass + * @param + * @return + */ + private static T doRequestZw(String url, Object param, Class resultClass) { + JSONObject paramJson = JSONObject.parseObject(JSONObject.toJSONString(param)); +// paramJson.put("md5key", generateSign(paramJson)); + log.info("doRequestZw >> 准备请求智网接口, url={}, param={}", url, paramJson.toJSONString()); + long currentTime = DateKit.currentTimeMillis(); + String responseStr; + try { + responseStr = HttpUtil.post(url, paramJson.toJSONString()); + log.info("doRequestZw >> 智网接口响应, 耗时={}ms, url={}, param={}, response={}", DateKit.currentTimeMillis() - currentTime, url, paramJson, responseStr); + return JSONObject.parseObject(responseStr, resultClass); + } catch (Exception e) { + log.error("doRequestZw >> 请求智网接口失败, url={}, param={}", url, paramJson, e); + throw new BizException("请求智网接口失败"); + } + } + + private static String generateSign(Map params) { + if (params == null) { + return null; + } else { + StringBuffer content = new StringBuffer(); + List keys = new ArrayList(params.keySet()); + Collections.sort(keys); + + for (int i = 0; i < keys.size(); ++i) { + String key = keys.get(i); + String value = params.get(key) == null ? "" : params.get(key).toString(); + content.append((i == 0 ? "" : "&") + key + "=" + value); + } + return JeepayKit.md5(content.toString(), "UTF-8").toUpperCase(); + } + } + + public BaseResponse soundPayMsg(PayMsgRequest payMsgRequest) { + return doRequestZw(ZwConstants.ZW_URL_HOST + ZwConstants.ZW_PAY_SPEAKER, payMsgRequest, BaseResponse.class); + } + + public static BaseResponse soundNotifyMsg(NotifyMsgRequest notifyMsgRequest) { + return doRequestZw(ZwConstants.ZW_URL_HOST + ZwConstants.ZW_4G_PAY_SPEAKER, notifyMsgRequest, BaseResponse.class); + } + + public static BaseResponse cloudPrint(PrintRequest printRequest) { + return doRequestZw(ZwConstants.ZW_URL_HOST + ZwConstants.ZW_CLOUD_PRINT, printRequest, BaseResponse.class); + } + + public static BaseResponse updatePayParam(UpdatePayParamRequest updatePayParamRequest) { + return doRequestZw(ZwConstants.ZW_URL_HOST + ZwConstants.ZW_UPDATE_PAY_PARAM, updatePayParamRequest, BaseResponse.class); + } + + /** 生成小票 **/ + public static List getPrintPd(PayOrderInfo4Device payOrderInfo) { + List printPdRequests = new ArrayList<>(); + PrintPdRequest printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("3"); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("支付凭证"); + printPdRequest.setAl("1"); + printPdRequest.setFs("3"); + printPdRequest.setTb("1"); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("4"); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("门店名称:" + payOrderInfo.getStoreName()); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("订 单 号:" + payOrderInfo.getPayOrderId()); + printPdRequests.add(printPdRequest); + +// printPdRequest = new PrintPdRequest(); +// printPdRequest.setTp("1"); +// printPdRequest.setCv("商户单号:" + payOrderInfo.getMchOrderNo()); +// printPdRequests.add(printPdRequest); + +// printPdRequest = new PrintPdRequest(); +// printPdRequest.setTp("1"); +// printPdRequest.setCv("支付状态:" + CS.PAY_STATE_MAP.get(bizRes.getState())); +// printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("支付方式:" + CS.PAY_WAY_CODE_TYPE_MAP.get(payOrderInfo.getWayCodeType())); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("下单时间:" + DateUtil.format(payOrderInfo.getCreatedAt(), DatePattern.NORM_DATETIME_PATTERN)); + printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("4"); + printPdRequests.add(printPdRequest); + +// printPdRequest = new PrintPdRequest(); +// printPdRequest.setTp("1"); +// printPdRequest.setCv("完成时间:" + CljDateUtil.conversionTime(bizRes.getSuccessTime().toString())); +// printPdRequests.add(printPdRequest); + + printPdRequest = new PrintPdRequest(); + printPdRequest.setTp("1"); + printPdRequest.setCv("交易金额:" + AmountUtil.convertCent2Dollar(payOrderInfo.getAmount().toString())); + printPdRequests.add(printPdRequest); + + return printPdRequests; + } +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/ZwConstants.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/ZwConstants.java new file mode 100644 index 0000000..459fd38 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/service/zw/uils/ZwConstants.java @@ -0,0 +1,41 @@ +/** + * cljpay.com + * Copyright (C) 2015-2023 All Rights Reserved. + */package com.jeequan.jeepay.thirdparty.service.zw.uils; + +/** + * @author yangjun + * @version ZwConstants.java, v 0.1 2023-02-20 10:12 yangjun + */ +public class ZwConstants { + + + public static final String ZW_URL_HOST = "https://open.smartlinkall.com/"; + + + /** + * 支付语音播报 + */ + public static final String ZW_PAY_SPEAKER = "paymsg"; + + /** + * 通知语音播报-4G + */ + public static final String ZW_4G_PAY_SPEAKER = "notifymsg"; + + /** + * 云打印-小票打印+语音播报 + */ + public static final String ZW_CLOUD_PRINT = "print"; + + /** + * 设置支付交易参数 (支付设备绑定) + */ + public static final String ZW_UPDATE_PAY_PARAM = "updatepaypara"; + + + /** + * 智网token + */ + public static final String ZW_TOKEN = "120565813432"; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ApiResBuilder.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ApiResBuilder.java new file mode 100644 index 0000000..49c861a --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ApiResBuilder.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.thirdparty.util; + + +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; + +/** + * api响应结果构造器 + * + * @author terrfly + * @date 2021/6/8 17:45 + */ +public class ApiResBuilder { + + /** 构建自定义响应对象, 默认响应成功 **/ + public static T buildSuccess(Class T){ + + try { + T result = (T)T.newInstance(); + return result; + + } catch (Exception e) { return null; } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ChannelCertConfigKitBean.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ChannelCertConfigKitBean.java new file mode 100644 index 0000000..b32cfab --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/ChannelCertConfigKitBean.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.thirdparty.util; + +import com.jeequan.jeepay.components.oss.config.OssYmlConfig; +import com.jeequan.jeepay.components.oss.constant.OssSavePlaceEnum; +import com.jeequan.jeepay.components.oss.constant.OssServiceTypeEnum; +import com.jeequan.jeepay.components.oss.service.IOssService; +import com.jeequan.jeepay.core.model.DBOSSConfig; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.service.impl.SysConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; + +/** + * 支付平台 获取系统文件工具类 + * + * @author terrfly + * @date 2021/6/8 17:45 + */ +@Component +public class ChannelCertConfigKitBean { + + @Autowired private OssYmlConfig ossYmlConfig; + @Autowired private SysConfigService sysConfigService; + + public String getCertFilePath(String certFilePath){ + return getCertFile(certFilePath).getAbsolutePath(); + } + + public File getCertFile(String certFilePath){ + File certFile = new File(ossYmlConfig.getOss().getFilePrivatePath() + File.separator + certFilePath); + + if(certFile.exists()){ // 本地存在直接返回 + return certFile; + } + + // 以下为 文件不存在的处理方式 + + // 是否本地存储 + boolean isLocalSave = OssServiceTypeEnum.LOCAL.getServiceName().equals(sysConfigService.getOssConfig().getOssUseType()); + + // 本地存储 & 文件不存在 + if(isLocalSave){ + return certFile; + } + + // 已经向oss请求并且返回了空文件时 + if(new File(certFile.getAbsolutePath() + ".notexists").exists()){ + return certFile; + } + + // 当文件夹不存在时, 需要创建。 + if(!certFile.getParentFile().exists()){ + certFile.getParentFile().mkdirs(); + } + + // 请求下载并返回 新File + return downloadFile(certFilePath, certFile); + } + + + /** 下载文件 **/ + private synchronized File downloadFile(String dbCertFilePath, File certFile){ + + //请求文件并写入 + boolean isSuccess = getOssService().downloadFile(OssSavePlaceEnum.PRIVATE, dbCertFilePath, certFile.getAbsolutePath()); + + // 下载成功 返回新的File对象 + if(isSuccess) { + return new File(certFile.getAbsolutePath()); + } + + // 下载失败, 写入.notexists文件, 避免那下次再次下载影响效率。 + + try { + new File(certFile.getAbsolutePath() + ".notexists").createNewFile(); + } catch (IOException e) { + } + + return certFile; + } + + private IOssService getOssService(){ + + DBOSSConfig dbossConfig = sysConfigService.getOssConfig(); + return SpringBeansUtil.getBean(dbossConfig.getOssUseType() + "OssService", IOssService.class); + + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/CodeImgUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/CodeImgUtil.java new file mode 100644 index 0000000..5039c64 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/CodeImgUtil.java @@ -0,0 +1,365 @@ +package com.jeequan.jeepay.thirdparty.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.zxing.*; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URL; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 二维码生成器 + * + * @author terrfly + * @date 2021/6/8 17:54 + */ +public class CodeImgUtil { + + private static final Logger _log = LoggerFactory.getLogger(CodeImgUtil.class); + + // 二维码尺寸List + private static List sizeList = new ArrayList(); + + static { + sizeList.add(258); + sizeList.add(344); + sizeList.add(430); + sizeList.add(860); + sizeList.add(1280); + } + + public static List getEwmSizeList() { + return sizeList; + } + + + // 图片宽度的一般 + private static final int IMAGE_WIDTH = 25; + private static final int IMAGE_HEIGHT = 25; + private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; + private static final int FRAME_WIDTH = 2; + + // 二维码写码器 + private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); + + /** + * + * @param content + * 二维码显示的文本 + * @param width + * 二维码的宽度 + * @param height + * 二维码的高度 + * @param srcImagePath + * 中间嵌套的图片 + * @param destImagePath + * 二维码生成的地址 + */ + public static void encode(String content, int width, int height, + String srcImagePath, String destImagePath, String fileName) { + try { + File dir = new File(destImagePath); + _log.error("==================" + destImagePath); + _log.error("==================" + srcImagePath); + if (!dir.exists()) { + _log.error("==================notExist"); + boolean result = dir.mkdirs(); + _log.error("==================midirsResult" + result); + } + // ImageIO.write 参数 1、BufferedImage 2、输出的格式 3、输出的文件 + ImageIO.write(genBarcode(content, width, height, srcImagePath), + "jpg", new File(destImagePath + fileName)); + + } catch (Exception e) { + _log.error("生成二维码出错", e); + } + } + + /** + * 得到BufferedImage + * + * @param content + * 二维码显示的文本 + * @param width + * 二维码的宽度 + * @param height + * 二维码的高度 + * @param srcImagePath + * 中间嵌套的图片 + * @return + * @throws WriterException + * @throws IOException + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static BufferedImage genBarcode(String content, int width, + int height, String srcImagePath) throws WriterException, + IOException { + // 读取源图像 + BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, + IMAGE_HEIGHT, false); + + int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; + for (int i = 0; i < scaleImage.getWidth(); i++) { + for (int j = 0; j < scaleImage.getHeight(); j++) { + srcPixels[i][j] = scaleImage.getRGB(i, j); + } + } + + java.util.Hashtable hint = new java.util.Hashtable(); + hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); + hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hint.put(EncodeHintType.MARGIN, 1); + // 生成二维码 + BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, + width, height, hint); + + // 二维矩阵转为一维像素数组 + int halfW = matrix.getWidth() / 2; + int halfH = matrix.getHeight() / 2; + int[] pixels = new int[width * height]; + + for (int y = 0; y < matrix.getHeight(); y++) { + for (int x = 0; x < matrix.getWidth(); x++) { + // 读取图片 + if (x > halfW - IMAGE_HALF_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + && y > halfH - IMAGE_HALF_WIDTH + && y < halfH + IMAGE_HALF_WIDTH) { + pixels[y * width + x] = srcPixels[x - halfW + + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; + } + // 在图片四周形成边框 + else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + - IMAGE_HALF_WIDTH + FRAME_WIDTH) + || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH + && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH + && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { + pixels[y * width + x] = 0xfffffff; + } else { + // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; + pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 + : 0xfffffff; + } + } + } + + BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + image.getRaster().setDataElements(0, 0, width, height, pixels); + + return image; + } + + /** + * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 + * + * @param srcImageFile + * 源文件地址 + * @param height + * 目标高度 + * @param width + * 目标宽度 + * @param hasFiller + * 比例不对时是否需要补白:true为补白; false为不补白; + * @throws IOException + */ + private static BufferedImage scale(String srcImageFile, int height, + int width, boolean hasFiller) throws IOException { + double ratio = 0.0; // 缩放比例 + + URL url = new URL(srcImageFile); + + BufferedImage srcImage = ImageIO.read(url); + Image destImage = srcImage.getScaledInstance(width, height, + BufferedImage.SCALE_SMOOTH); + // 计算比例 + if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { + if (srcImage.getHeight() > srcImage.getWidth()) { + ratio = (new Integer(height)).doubleValue() + / srcImage.getHeight(); + } else { + ratio = (new Integer(width)).doubleValue() + / srcImage.getWidth(); + } + AffineTransformOp op = new AffineTransformOp(AffineTransform + .getScaleInstance(ratio, ratio), null); + destImage = op.filter(srcImage, null); + } + if (hasFiller) {// 补白 + BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + Graphics2D graphic = image.createGraphics(); + graphic.setColor(Color.white); + graphic.fillRect(0, 0, width, height); + if (width == destImage.getWidth(null)) { + graphic.drawImage(destImage, 0, (height - destImage + .getHeight(null)) / 2, destImage.getWidth(null), + destImage.getHeight(null), Color.white, null); + } else { + graphic.drawImage(destImage, + (width - destImage.getWidth(null)) / 2, 0, destImage + .getWidth(null), destImage.getHeight(null), + Color.white, null); + } + graphic.dispose(); + destImage = image; + } + return (BufferedImage) destImage; + } + + /** + * 生成图像 + * filePath 存放图片的路径 + * fileName 图片的名称 + * info 生成图片的链接地址(例如:weixin://wxpay/s/Anp43md) + * width 图片的宽度 + * height 图片的高度 + * @throws WriterException + * @throws IOException + */ + public static String codeImgEncode(String filePath, String fileName, String info, int width, int height) throws WriterException, IOException { + String format="png"; + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + BitMatrix bitMatrix = new MultiFormatWriter().encode(info, + BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 + Path path = FileSystems.getDefault().getPath(filePath, fileName); + File dir = new File(filePath); + _log.error("==================" + filePath); + if (!dir.exists()) { + _log.error("==================notExist"); + boolean result = dir.mkdirs(); + _log.error("==================midirsResult" + result); + } + MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 输出图像 + return path.toString(); + } + + + public static void writeQrCode(OutputStream stream, String info, int width, int height) throws WriterException, IOException { + String format="png"; + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.MARGIN,0); + BitMatrix bitMatrix = new MultiFormatWriter().encode(info, + BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 + bitMatrix = deleteWhite(bitMatrix); + BufferedImage bi = MatrixToImageWriter.toBufferedImage(bitMatrix); + bi = zoomInImage(bi,width,height); + ImageIO.write(bi,format,stream); // 输出图像 + //MatrixToImageWriter.writeToStream(bitMatrix, format, stream);// 输出图像 + } + + /** + * 条形码编码 + * + * @param contents + * @param width + * @param height + * @param stream + */ + public static void writeBarCode(OutputStream stream, String contents, int width, int height) { + int codeWidth = 3 + // start guard + (7 * 6) + // left bars + 5 + // middle guard + (7 * 6) + // right bars + 3; // end guard + codeWidth = Math.max(codeWidth, width); + try { + String format="png"; + BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, + BarcodeFormat.CODE_128, codeWidth, height, null); + MatrixToImageWriter.writeToStream(bitMatrix, format, stream);// 输出图像 + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * 解析图像 + */ + public static void codeImgDecode() { + String filePath = "D://zxing.png"; + BufferedImage image; + try { + image = ImageIO.read(new File(filePath)); + LuminanceSource source = new BufferedImageLuminanceSource(image); + Binarizer binarizer = new HybridBinarizer(source); + BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); + Map hints = new HashMap(); + hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); + Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码 + JSONObject content = JSON.parseObject(result.getText()); + System.out.println("图片中内容: "); + System.out.println("author: " + content.getString("author")); + System.out.println("zxing: " + content.getString("zxing")); + System.out.println("图片中格式: "); + System.out.println("encode: " + result.getBarcodeFormat()); + } catch (IOException e) { + e.printStackTrace(); + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + + /** + * 去除白边 + * */ + private static BitMatrix deleteWhite(BitMatrix matrix) { + int[] rec = matrix.getEnclosingRectangle(); + int resWidth = rec[2] + 1; + int resHeight = rec[3] + 1; + + BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); + resMatrix.clear(); + for (int i = 0; i < resWidth; i++) { + for (int j = 0; j < resHeight; j++) { + if (matrix.get(i + rec[0], j + rec[1])) { + resMatrix.set(i, j); + } + } + } + return resMatrix; + } + + public static BufferedImage zoomInImage(BufferedImage originalImage, int wigth, int height){ + BufferedImage newImage = new BufferedImage(wigth,height,originalImage.getType()); + Graphics g = newImage.getGraphics(); + g.drawImage(originalImage,0,0,wigth,height,null); + g.dispose(); + return newImage; + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/OCRUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/OCRUtil.java new file mode 100644 index 0000000..b14e8d7 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/OCRUtil.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.thirdparty.util; + +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.OCRImgParams; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; + +/** + * OCR工具类 + * + * @author xiaoyu + * @date 2022/1/12 14:52 + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class OCRUtil { + + /** + * @author: xiaoyu + * @date: 2022/1/13 14:32 + * @describe: 身份证有效期格式转化为通用格式 + */ + public static void setIdCardDate(String validPeriod, OCRImgParams ocrImgParams) { + try { + String[] strings = validPeriod.split("-"); + String startTime = strings[0]; + String endTime = strings[1]; + if (!"长期".equals(endTime)) { + endTime = formatDate(endTime); + } + // 身份证有效期 + ocrImgParams.setIdcardEffectBegin(formatDate(startTime)); + ocrImgParams.setIdcardEffectEnd(endTime); + } catch (Exception e) { + log.error("身份证有效期格式化异常"); + } + } + + /** + * @author: xiaoyu + * @date: 2022/1/13 14:32 + * @describe: 营业执照有效期格式转化为通用格式 + */ + public static void setLicenseDate(String validPeriod, OCRImgParams ocrImgParams) { + try { + String[] strings = validPeriod.split("至"); + String startTime = strings[0]; + String endTime = strings[1]; + if (!"长期".equals(endTime)) { + endTime = formatDate(endTime); + } + // 身份证有效期 + ocrImgParams.setLicenseEffectBegin(formatDate(startTime)); + ocrImgParams.setLicenseEffectEnd(endTime); + + } catch (Exception e) { + log.error("营业执照有效期格式化异常"); + } + } + + /** + * @author: xiaoyu + * @date: 2022/1/13 14:32 + * @describe: 营业执照有效期格式转化为通用格式 + */ + public static void setLicenseDateAli(JSONObject dateJson, OCRImgParams ocrImgParams) { + try { + String startTime = dateJson.getString("validFromDate"); + String endTime = dateJson.getString("validToDate"); + if (StringUtils.isEmpty(endTime) || "29991231".equals(endTime)) { + endTime = "长期"; + } else { + endTime = formatDate(endTime); + } + // 身份证有效期 + ocrImgParams.setLicenseEffectBegin(formatDate(startTime)); + ocrImgParams.setLicenseEffectEnd(endTime); + + } catch (Exception e) { + log.error("营业执照有效期格式化异常"); + } + } + + /** + * @author: xiaoyu + * @date: 2022/1/13 15:02 + * @describe: 日期格式化 yyyy-MM-dd + */ + public static String formatDate(String dateTime) { + Date date = DateUtil.parse(dateTime); + return DateUtil.format(date, "yyyy-MM-dd"); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/PaywayUtil.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/PaywayUtil.java new file mode 100644 index 0000000..a1236aa --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/PaywayUtil.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.thirdparty.util; + +import cn.hutool.core.util.StrUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.interfaces.paychannel.IPaymentService; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; + +import static java.lang.System.out; + +/** + * 支付方式动态调用Utils + * @author terrfly + * @date 2021/6/8 17:46 + */ +public class PaywayUtil { + + private static final String PAYWAY_PACKAGE_NAME = "payway"; + private static final String PAYWAYV3_PACKAGE_NAME = "paywayV3"; + + /** 获取真实的支付方式Service **/ + public static IPaymentService getRealPaywayService(Object obj, String wayCode){ + + try { + + //下划线转换驼峰 & 首字母大写 + String clsName = StrUtil.upperFirst(StrUtil.toCamelCase(wayCode.toLowerCase())); + return (IPaymentService) SpringBeansUtil.getBean( + Class.forName(obj.getClass().getPackage().getName() + + "." + PAYWAY_PACKAGE_NAME + + "." + clsName) + ); + + } catch (ClassNotFoundException e) { + return null; + } + } + + /** 获取微信V3真实的支付方式Service **/ + public static IPaymentService getRealPaywayV3Service(Object obj, String wayCode){ + + try { + + //下划线转换驼峰 & 首字母大写 + String clsName = StrUtil.upperFirst(StrUtil.toCamelCase(wayCode.toLowerCase())); + return (IPaymentService) SpringBeansUtil.getBean( + Class.forName(obj.getClass().getPackage().getName() + + "." + PAYWAYV3_PACKAGE_NAME + + "." + clsName) + ); + + } catch (ClassNotFoundException e) { + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/WxLiteCodeUtils.java b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/WxLiteCodeUtils.java new file mode 100644 index 0000000..4f14c2c --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/java/com/jeequan/jeepay/thirdparty/util/WxLiteCodeUtils.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.thirdparty.util; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import me.chanjar.weixin.common.error.WxErrorException; + +/*** + * 单独写获取 code2Session的接口 + * wxJava每次都会调用: session, 如果两个同时调用可能造成互相占用的情况。 + * + * @author terrfly + * @date 2023/9/9 16:42 + */ +public class WxLiteCodeUtils { + + public static final String REQ_URL = "https://api.weixin.qq.com/sns/jscode2session"; + + // https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html + public static WxMaJscode2SessionResult code2OpenId(String appId, String secret, String jsCode) throws WxErrorException { + + JSONObject params = new JSONObject(); + params.put("appid", appId); + params.put("secret", secret); + params.put("js_code", jsCode); + params.put("grant_type", "authorization_code"); + + + String res = HttpUtil.get(REQ_URL, params); + + if(res == null){ + throw new WxErrorException("返回数据为空"); + } + + JSONObject resObject = JSONObject.parseObject(res); + + if(resObject.getInteger("errcode") != null && resObject.getInteger("errcode") != 0){ + throw new WxErrorException(resObject.getString("errmsg")); + } + + WxMaJscode2SessionResult result = new WxMaJscode2SessionResult(); + result.setSessionKey(resObject.getString("session_key")); + result.setUnionid(resObject.getString("unionid")); + result.setOpenid(resObject.getString("openid")); + return result; + } + + // https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html + public static WxMaJscode2SessionResult code2OpenId(WxMaService wxMaService, String jsCode) throws WxErrorException { + return code2OpenId(wxMaService.getWxMaConfig().getAppid(), wxMaService.getWxMaConfig().getSecret(), jsCode); + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/.keep b/jeepay-components/jeepay-components-3rd/src/main/resources/.keep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodeCorporate.json b/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodeCorporate.json new file mode 100644 index 0000000..d780fc6 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodeCorporate.json @@ -0,0 +1 @@ +[{"bank_alias":"招商银行","need_bank_branch":false,"account_bank":"招商银行","account_bank_code":1001,"bank_alias_code":"1000009561"},{"bank_alias":"工商银行","need_bank_branch":false,"account_bank":"工商银行","account_bank_code":1002,"bank_alias_code":"1000009547"},{"bank_alias":"建设银行","need_bank_branch":false,"account_bank":"建设银行","account_bank_code":1003,"bank_alias_code":"1000009550"},{"bank_alias":"浦发银行","need_bank_branch":false,"account_bank":"浦发银行","account_bank_code":1004,"bank_alias_code":"1000009563"},{"bank_alias":"农业银行","need_bank_branch":false,"account_bank":"农业银行","account_bank_code":1005,"bank_alias_code":"1000009548"},{"bank_alias":"民生银行","need_bank_branch":false,"account_bank":"民生银行","account_bank_code":1006,"bank_alias_code":"1000009558"},{"bank_alias":"兴业银行","need_bank_branch":false,"account_bank":"兴业银行","account_bank_code":1009,"bank_alias_code":"1000009562"},{"bank_alias":"平安银行","need_bank_branch":false,"account_bank":"平安银行","account_bank_code":1010,"bank_alias_code":"1000009560"},{"bank_alias":"交通银行","need_bank_branch":false,"account_bank":"交通银行","account_bank_code":1020,"bank_alias_code":"1000009554"},{"bank_alias":"中信银行","need_bank_branch":false,"account_bank":"中信银行","account_bank_code":1021,"bank_alias_code":"1000009555"},{"bank_alias":"光大银行","need_bank_branch":false,"account_bank":"光大银行","account_bank_code":1022,"bank_alias_code":"1000009556"},{"bank_alias":"上海银行","need_bank_branch":false,"account_bank":"上海银行","account_bank_code":1024,"bank_alias_code":"1000009569"},{"bank_alias":"华夏银行","need_bank_branch":false,"account_bank":"华夏银行","account_bank_code":1025,"bank_alias_code":"1000009557"},{"bank_alias":"中国银行","need_bank_branch":false,"account_bank":"中国银行","account_bank_code":1026,"bank_alias_code":"1000009549"},{"bank_alias":"广发银行","need_bank_branch":false,"account_bank":"广发银行","account_bank_code":1027,"bank_alias_code":"1000009559"},{"bank_alias":"南京银行","need_bank_branch":false,"account_bank":"南京银行","account_bank_code":1054,"bank_alias_code":"1000005234"},{"bank_alias":"宁波银行","need_bank_branch":false,"account_bank":"宁波银行","account_bank_code":1056,"bank_alias_code":"1000005229"},{"bank_alias":"邮政储蓄银行","need_bank_branch":false,"account_bank":"邮政储蓄银行","account_bank_code":1066,"bank_alias_code":"1000009571"},{"bank_alias":"莱商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000000001"},{"bank_alias":"廊坊银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005186"},{"bank_alias":"泰安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005187"},{"bank_alias":"凉山州商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005188"},{"bank_alias":"营口沿海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005189"},{"bank_alias":"昆仑银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005190"},{"bank_alias":"云南红塔银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005191"},{"bank_alias":"邢台银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005192"},{"bank_alias":"贵州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005193"},{"bank_alias":"江苏长江商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005195"},{"bank_alias":"广西北部湾银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005196"},{"bank_alias":"乐山市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005198"},{"bank_alias":"邯郸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005199"},{"bank_alias":"广东南粤银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005200"},{"bank_alias":"威海市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005201"},{"bank_alias":"宁波通商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005203"},{"bank_alias":"齐鲁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005204"},{"bank_alias":"甘肃银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005205"},{"bank_alias":"本溪银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005206"},{"bank_alias":"沧州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005207"},{"bank_alias":"柳州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005208"},{"bank_alias":"厦门银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005209"},{"bank_alias":"华融湘江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005210"},{"bank_alias":"辽阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005211"},{"bank_alias":"林州中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005212"},{"bank_alias":"天津银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005213"},{"bank_alias":"福建海峡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005214"},{"bank_alias":"晋中银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005216"},{"bank_alias":"遂宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005218"},{"bank_alias":"鞍山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005219"},{"bank_alias":"遵义市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005220"},{"bank_alias":"阜新银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005221"},{"bank_alias":"绍兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005222"},{"bank_alias":"临商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005224"},{"bank_alias":"龙江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005225"},{"bank_alias":"贵阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005226"},{"bank_alias":"阳泉市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005227"},{"bank_alias":"吉林银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005228"},{"bank_alias":"九江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005230"},{"bank_alias":"嘉兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005231"},{"bank_alias":"泸州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005232"},{"bank_alias":"苏州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005233"},{"bank_alias":"铁岭银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005235"},{"bank_alias":"自贡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005236"},{"bank_alias":"济宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005237"},{"bank_alias":"上饶银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005238"},{"bank_alias":"唐山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005240"},{"bank_alias":"西安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005241"},{"bank_alias":"营口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005242"},{"bank_alias":"乌鲁木齐银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005243"},{"bank_alias":"雅安市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005244"},{"bank_alias":"宜宾市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005245"},{"bank_alias":"富滇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005247"},{"bank_alias":"张家口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005248"},{"bank_alias":"东营银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005249"},{"bank_alias":"盛京银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005250"},{"bank_alias":"河北银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005251"},{"bank_alias":"广东华兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005252"},{"bank_alias":"海南银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005254"},{"bank_alias":"哈尔滨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005255"},{"bank_alias":"赣州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005256"},{"bank_alias":"达州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005257"},{"bank_alias":"青海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005258"},{"bank_alias":"曲靖市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005259"},{"bank_alias":"成都银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005260"},{"bank_alias":"长安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005261"},{"bank_alias":"盘锦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005262"},{"bank_alias":"日照银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005263"},{"bank_alias":"攀枝花市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005264"},{"bank_alias":"承德银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005265"},{"bank_alias":"烟台银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005266"},{"bank_alias":"绵阳市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005267"},{"bank_alias":"朝阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005268"},{"bank_alias":"台州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005269"},{"bank_alias":"广州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005270"},{"bank_alias":"桂林银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005271"},{"bank_alias":"金华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005273"},{"bank_alias":"郑州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005274"},{"bank_alias":"丹东银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005275"},{"bank_alias":"晋城银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005276"},{"bank_alias":"蒙商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005277"},{"bank_alias":"鄂尔多斯银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005278"},{"bank_alias":"潍坊银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005279"},{"bank_alias":"焦作中旅银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005280"},{"bank_alias":"汉口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005281"},{"bank_alias":"桂林市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005282"},{"bank_alias":"浙江民泰商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005283"},{"bank_alias":"浙江稠州商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005284"},{"bank_alias":"西藏银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005286"},{"bank_alias":"兰州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005287"},{"bank_alias":"江西银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005288"},{"bank_alias":"乌海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005289"},{"bank_alias":"保定银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005290"},{"bank_alias":"珠海华润银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005291"},{"bank_alias":"四川天府银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005294"},{"bank_alias":"泸州市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005295"},{"bank_alias":"达州市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005296"},{"bank_alias":"青岛银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005297"},{"bank_alias":"内蒙古银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005298"},{"bank_alias":"葫芦岛银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005299"},{"bank_alias":"泉州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005303"},{"bank_alias":"大连银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005304"},{"bank_alias":"新疆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005305"},{"bank_alias":"宁波东海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005308"},{"bank_alias":"石嘴山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005309"},{"bank_alias":"抚顺银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005311"},{"bank_alias":"重庆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005312"},{"bank_alias":"温州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005313"},{"bank_alias":"齐商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005314"},{"bank_alias":"平顶山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005315"},{"bank_alias":"东莞银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005316"},{"bank_alias":"锦州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005317"},{"bank_alias":"新疆汇和银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005318"},{"bank_alias":"宁夏银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005319"},{"bank_alias":"湖南岳阳湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005320"},{"bank_alias":"尚志惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005321"},{"bank_alias":"天津市蓟州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005322"},{"bank_alias":"锦州松山农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005323"},{"bank_alias":"郑州金水厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005324"},{"bank_alias":"云南西山渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005325"},{"bank_alias":"新疆石河子交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005326"},{"bank_alias":"永城齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005327"},{"bank_alias":"文山马关长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005329"},{"bank_alias":"九江共青村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005331"},{"bank_alias":"峨眉山中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005332"},{"bank_alias":"沈阳于洪永安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005333"},{"bank_alias":"双城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005334"},{"bank_alias":"重庆璧山工银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005335"},{"bank_alias":"安徽怀宁江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005336"},{"bank_alias":"福泉富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005337"},{"bank_alias":"浙江平阳浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005338"},{"bank_alias":"湖南新邵湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005339"},{"bank_alias":"资兴浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005340"},{"bank_alias":"浙江淳安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005341"},{"bank_alias":"铁岭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005342"},{"bank_alias":"四平铁东德丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005343"},{"bank_alias":"滦南中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005345"},{"bank_alias":"四川大竹渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005346"},{"bank_alias":"张家口宣化家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005347"},{"bank_alias":"苏州常熟中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005348"},{"bank_alias":"哈尔滨阿城农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005349"},{"bank_alias":"茂名高州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005351"},{"bank_alias":"湖南道县神农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005352"},{"bank_alias":"浙江富阳恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005353"},{"bank_alias":"安徽涡阳湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005354"},{"bank_alias":"保康楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005355"},{"bank_alias":"曲周恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005356"},{"bank_alias":"贵阳小河科技村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005357"},{"bank_alias":"延寿融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005358"},{"bank_alias":"惠安中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005359"},{"bank_alias":"广水楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005361"},{"bank_alias":"和顺县贵都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005362"},{"bank_alias":"望江新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005363"},{"bank_alias":"山东莒南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005364"},{"bank_alias":"昆明盘龙兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005365"},{"bank_alias":"四平铁西敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005366"},{"bank_alias":"含山惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005367"},{"bank_alias":"巨鹿融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005368"},{"bank_alias":"云南大理渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005369"},{"bank_alias":"鄢陵郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005370"},{"bank_alias":"天津宁河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005371"},{"bank_alias":"个旧沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005372"},{"bank_alias":"界首中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005373"},{"bank_alias":"四子王蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005374"},{"bank_alias":"湖南华容星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005375"},{"bank_alias":"浙江天台民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005376"},{"bank_alias":"天津华明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005377"},{"bank_alias":"土默特右旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005378"},{"bank_alias":"竹山楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005379"},{"bank_alias":"陕西商南聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005380"},{"bank_alias":"固安恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005381"},{"bank_alias":"安徽凤台通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005382"},{"bank_alias":"云南香格里拉渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005383"},{"bank_alias":"围场满族蒙古族自治县华商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005384"},{"bank_alias":"旌德民商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005385"},{"bank_alias":"滑县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005386"},{"bank_alias":"江苏海门中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005387"},{"bank_alias":"任县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005388"},{"bank_alias":"贵阳云岩富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005389"},{"bank_alias":"成都双流诚民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005390"},{"bank_alias":"淮安淮阴兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005391"},{"bank_alias":"庆城县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005392"},{"bank_alias":"睢县德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005393"},{"bank_alias":"兰州安宁神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005394"},{"bank_alias":"宁夏西吉汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005395"},{"bank_alias":"大厂回族自治县新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005396"},{"bank_alias":"四川北川羌族富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005397"},{"bank_alias":"福建石狮渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005399"},{"bank_alias":"涉县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005400"},{"bank_alias":"安徽青阳九华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005401"},{"bank_alias":"辽宁北镇锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005402"},{"bank_alias":"东宁润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005403"},{"bank_alias":"南康赣商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005404"},{"bank_alias":"深圳福田银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005406"},{"bank_alias":"西藏堆龙民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005407"},{"bank_alias":"晴隆兴安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005409"},{"bank_alias":"禹州新民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005410"},{"bank_alias":"依安润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005411"},{"bank_alias":"南宁武鸣漓江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005412"},{"bank_alias":"讷河融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005413"},{"bank_alias":"广西鹿寨渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005414"},{"bank_alias":"京山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005415"},{"bank_alias":"重庆彭水民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005416"},{"bank_alias":"依兰惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005417"},{"bank_alias":"江苏灌云民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005418"},{"bank_alias":"开远沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005420"},{"bank_alias":"宁夏盐池汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005421"},{"bank_alias":"包头市高新银通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005423"},{"bank_alias":"鹤山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005424"},{"bank_alias":"藁城恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005425"},{"bank_alias":"乐平融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005427"},{"bank_alias":"乌鲁木齐米东浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005429"},{"bank_alias":"进贤瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005430"},{"bank_alias":"陕西汉中南郑汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005431"},{"bank_alias":"南宁隆安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005432"},{"bank_alias":"深泽利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005433"},{"bank_alias":"安阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005434"},{"bank_alias":"喀喇沁玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005435"},{"bank_alias":"长春净月榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005436"},{"bank_alias":"湖南浏阳江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005437"},{"bank_alias":"神农架楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005438"},{"bank_alias":"云霄润发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005439"},{"bank_alias":"辽宁灯塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005440"},{"bank_alias":"巫山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005441"},{"bank_alias":"辽宁太子河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005442"},{"bank_alias":"铜川耀州新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005443"},{"bank_alias":"赤峰市元宝山玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005444"},{"bank_alias":"无为徽银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005445"},{"bank_alias":"福建沙县渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005446"},{"bank_alias":"襄城汇浦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005447"},{"bank_alias":"蛟河吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005448"},{"bank_alias":"兰考齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005449"},{"bank_alias":"西安高陵阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005450"},{"bank_alias":"江苏丰县民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005451"},{"bank_alias":"济宁高新村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005452"},{"bank_alias":"青岛莱西元泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005453"},{"bank_alias":"重庆长寿中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005454"},{"bank_alias":"平舆玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005455"},{"bank_alias":"天长民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005456"},{"bank_alias":"正定恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005457"},{"bank_alias":"綦江民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005459"},{"bank_alias":"广东恩平汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005460"},{"bank_alias":"重庆市沙坪坝融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005461"},{"bank_alias":"伊川齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005462"},{"bank_alias":"古田刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005463"},{"bank_alias":"深圳龙岗鼎业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005464"},{"bank_alias":"平和润丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005465"},{"bank_alias":"秦皇岛抚宁家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005466"},{"bank_alias":"湖南邵阳湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005467"},{"bank_alias":"浙江武义中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005469"},{"bank_alias":"天津滨海江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005470"},{"bank_alias":"阳江阳春长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005471"},{"bank_alias":"句容苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005472"},{"bank_alias":"浙江定海德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005473"},{"bank_alias":"山东莱山齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005474"},{"bank_alias":"南漳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005476"},{"bank_alias":"黄梅中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005477"},{"bank_alias":"浙江永嘉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005478"},{"bank_alias":"池州贵池民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005479"},{"bank_alias":"师宗兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005480"},{"bank_alias":"湖南冷水江湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005481"},{"bank_alias":"紫云富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005482"},{"bank_alias":"鄂尔多斯市铁西蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005483"},{"bank_alias":"呼和浩特市赛罕金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005484"},{"bank_alias":"洛宁兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005485"},{"bank_alias":"偃师融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005487"},{"bank_alias":"海南保亭融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005488"},{"bank_alias":"灵山泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005489"},{"bank_alias":"武强家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005490"},{"bank_alias":"廊坊市安次区惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005491"},{"bank_alias":"平泉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005492"},{"bank_alias":"开封新东方村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005493"},{"bank_alias":"鄂尔多斯市天骄蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005494"},{"bank_alias":"抚州东乡富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005495"},{"bank_alias":"平昌农科村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005496"},{"bank_alias":"吉安稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005497"},{"bank_alias":"老河口中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005498"},{"bank_alias":"永兴沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005499"},{"bank_alias":"河南汝南泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005500"},{"bank_alias":"福建罗源汇融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005501"},{"bank_alias":"通化融达村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005502"},{"bank_alias":"容城邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005503"},{"bank_alias":"乌海市海勃湾黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005504"},{"bank_alias":"夏县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005505"},{"bank_alias":"五原蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005508"},{"bank_alias":"济阳北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005509"},{"bank_alias":"江西上栗富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005510"},{"bank_alias":"中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005511"},{"bank_alias":"重庆铜梁浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005512"},{"bank_alias":"浙江余杭德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005513"},{"bank_alias":"遵义红花岗富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005514"},{"bank_alias":"成都郫都中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005515"},{"bank_alias":"湖南新化星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005516"},{"bank_alias":"西安长安新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005517"},{"bank_alias":"洪湖融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005518"},{"bank_alias":"河南商水厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005519"},{"bank_alias":"泰州高港兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005520"},{"bank_alias":"长春宽城融汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005521"},{"bank_alias":"宁夏原州津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005522"},{"bank_alias":"辽宁喀左锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005523"},{"bank_alias":"铜仁丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005524"},{"bank_alias":"张家口万全家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005525"},{"bank_alias":"浙江诸暨联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005527"},{"bank_alias":"贺州八步东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005528"},{"bank_alias":"磁县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005529"},{"bank_alias":"通化二道江瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005530"},{"bank_alias":"韶山光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005531"},{"bank_alias":"福建新罗晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005532"},{"bank_alias":"自贡中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005533"},{"bank_alias":"宁夏彭阳贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005534"},{"bank_alias":"江苏东海张农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005535"},{"bank_alias":"临澧沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005536"},{"bank_alias":"浙江海盐湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005537"},{"bank_alias":"丰城顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005538"},{"bank_alias":"辽宁台安金安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005539"},{"bank_alias":"邯郸永年齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005540"},{"bank_alias":"浙江仙居富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005541"},{"bank_alias":"武川立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005542"},{"bank_alias":"甘肃泾川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005543"},{"bank_alias":"山东芝罘齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005545"},{"bank_alias":"福建平潭渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005546"},{"bank_alias":"陇南市武都金桥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005547"},{"bank_alias":"正阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005548"},{"bank_alias":"乌鲁木齐县利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005549"},{"bank_alias":"醴陵沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005551"},{"bank_alias":"晋中市榆次融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005553"},{"bank_alias":"会宁会师村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005554"},{"bank_alias":"五台莱商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005555"},{"bank_alias":"吕梁孝义汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005556"},{"bank_alias":"济南槐荫沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005557"},{"bank_alias":"本溪丰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005558"},{"bank_alias":"本溪同盛村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005559"},{"bank_alias":"福建闽侯民本村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005560"},{"bank_alias":"平凉市静宁成纪村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005561"},{"bank_alias":"浙江临海湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005562"},{"bank_alias":"穆棱远东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005563"},{"bank_alias":"海南五指山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005564"},{"bank_alias":"谷城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005565"},{"bank_alias":"福建政和泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005566"},{"bank_alias":"枣阳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005567"},{"bank_alias":"武汉江夏民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005568"},{"bank_alias":"湖北咸安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005569"},{"bank_alias":"茂名电白长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005570"},{"bank_alias":"公主岭华兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005571"},{"bank_alias":"西丰鹿城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005572"},{"bank_alias":"重庆黔江银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005573"},{"bank_alias":"富民浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005574"},{"bank_alias":"南昌新建恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005575"},{"bank_alias":"当阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005576"},{"bank_alias":"抚顺市清原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005577"},{"bank_alias":"鄄城包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005578"},{"bank_alias":"重庆云阳恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005579"},{"bank_alias":"杞县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005580"},{"bank_alias":"天津滨海德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005581"},{"bank_alias":"横峰恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005582"},{"bank_alias":"贵安新区发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005583"},{"bank_alias":"江苏江宁上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005584"},{"bank_alias":"昌图民祥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005585"},{"bank_alias":"安徽黟县新淮河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005586"},{"bank_alias":"瓦房店长兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005587"},{"bank_alias":"厦门同安农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005588"},{"bank_alias":"什邡市思源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005589"},{"bank_alias":"察哈尔右翼前旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005591"},{"bank_alias":"沈阳新民富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005592"},{"bank_alias":"武陟射阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005593"},{"bank_alias":"临沧临翔沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005594"},{"bank_alias":"贵定恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005595"},{"bank_alias":"茌平沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005596"},{"bank_alias":"浙江长兴联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005597"},{"bank_alias":"江苏大丰江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005598"},{"bank_alias":"河南西华厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005600"},{"bank_alias":"易门兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005601"},{"bank_alias":"台前德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005602"},{"bank_alias":"蓬溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005603"},{"bank_alias":"安龙兴龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005604"},{"bank_alias":"浙江海宁德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005605"},{"bank_alias":"重庆北碚稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005606"},{"bank_alias":"安徽肥西石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005607"},{"bank_alias":"湖南芷江湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005608"},{"bank_alias":"厦门翔安民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005609"},{"bank_alias":"大连经济技术开发区鑫汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005610"},{"bank_alias":"乌苏利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005612"},{"bank_alias":"平遥县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005613"},{"bank_alias":"天津宝坻浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005614"},{"bank_alias":"呼图壁津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005615"},{"bank_alias":"繁峙县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005616"},{"bank_alias":"临清沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005617"},{"bank_alias":"汨罗中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005618"},{"bank_alias":"大安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005619"},{"bank_alias":"上海嘉定洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005620"},{"bank_alias":"湖南汝城新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005621"},{"bank_alias":"深圳宝安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005622"},{"bank_alias":"纳雍富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005623"},{"bank_alias":"浙江青田中银富登华侨村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005624"},{"bank_alias":"汶上中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005625"},{"bank_alias":"白山江源汇恒村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005626"},{"bank_alias":"安徽长丰科源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005627"},{"bank_alias":"阳信河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005628"},{"bank_alias":"平定县昌都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005630"},{"bank_alias":"三都富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005631"},{"bank_alias":"册亨富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005632"},{"bank_alias":"江苏丹徒蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005633"},{"bank_alias":"广州花都稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005634"},{"bank_alias":"盂县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005635"},{"bank_alias":"溧阳浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005636"},{"bank_alias":"安丘北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005637"},{"bank_alias":"五莲中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005638"},{"bank_alias":"湖南新宁潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005639"},{"bank_alias":"图们敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005641"},{"bank_alias":"青岛城阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005642"},{"bank_alias":"始兴大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005643"},{"bank_alias":"赤水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005645"},{"bank_alias":"浙江平湖工银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005646"},{"bank_alias":"广西鱼峰信合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005647"},{"bank_alias":"安徽霍邱联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005648"},{"bank_alias":"江苏灌南民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005649"},{"bank_alias":"凯里东南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005650"},{"bank_alias":"湖北麻城汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005651"},{"bank_alias":"云南安宁稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005652"},{"bank_alias":"广西桂平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005653"},{"bank_alias":"保山龙陵长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005654"},{"bank_alias":"浙江舟山普陀稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005655"},{"bank_alias":"高碑店中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005656"},{"bank_alias":"仙桃楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005657"},{"bank_alias":"江苏金湖民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005659"},{"bank_alias":"鄂托克前旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005660"},{"bank_alias":"云南祥云渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005661"},{"bank_alias":"彭州民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005663"},{"bank_alias":"萍乡安源富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005664"},{"bank_alias":"曲阳中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005666"},{"bank_alias":"淮安清河兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005668"},{"bank_alias":"太原市尖草坪区信都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005669"},{"bank_alias":"秭归兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005670"},{"bank_alias":"阜新农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005671"},{"bank_alias":"南充嘉陵中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005672"},{"bank_alias":"四川成都龙泉驿稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005673"},{"bank_alias":"乐山嘉州民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005674"},{"bank_alias":"江苏泗洪东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005675"},{"bank_alias":"敖汉惠农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005676"},{"bank_alias":"北京通州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005678"},{"bank_alias":"江苏锡山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005679"},{"bank_alias":"江西上高富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005680"},{"bank_alias":"桂阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005681"},{"bank_alias":"湖南南县湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005683"},{"bank_alias":"监利中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005684"},{"bank_alias":"余姚通济村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005685"},{"bank_alias":"江西兴国新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005686"},{"bank_alias":"光泽刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005688"},{"bank_alias":"云南马龙北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005689"},{"bank_alias":"威宁富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005690"},{"bank_alias":"镇宁汇商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005691"},{"bank_alias":"泰和中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005692"},{"bank_alias":"上海奉贤浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005694"},{"bank_alias":"祁县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005695"},{"bank_alias":"青龙融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005696"},{"bank_alias":"丹寨富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005697"},{"bank_alias":"林芝民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005698"},{"bank_alias":"江苏宿豫东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005699"},{"bank_alias":"枣强丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005700"},{"bank_alias":"兴仁振兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005701"},{"bank_alias":"敦煌市金盛村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005702"},{"bank_alias":"浙江三门银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005705"},{"bank_alias":"新干中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005706"},{"bank_alias":"潼南民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005707"},{"bank_alias":"交城县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005708"},{"bank_alias":"泸县元通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005711"},{"bank_alias":"文水县润都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005712"},{"bank_alias":"金溪抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005713"},{"bank_alias":"郑州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005714"},{"bank_alias":"资阳民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005715"},{"bank_alias":"新津珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005716"},{"bank_alias":"湘乡市村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005717"},{"bank_alias":"山东平邑汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005718"},{"bank_alias":"庄河汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005719"},{"bank_alias":"湖南邵东湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005720"},{"bank_alias":"南皮融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005721"},{"bank_alias":"长春二道农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005722"},{"bank_alias":"同江汇鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005723"},{"bank_alias":"枞阳泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005725"},{"bank_alias":"霞浦刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005727"},{"bank_alias":"福建永安汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005728"},{"bank_alias":"沿河长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005729"},{"bank_alias":"抚顺东洲抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005730"},{"bank_alias":"湖南津市湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005731"},{"bank_alias":"新安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005732"},{"bank_alias":"崇州上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005733"},{"bank_alias":"定安合丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005734"},{"bank_alias":"武定兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005735"},{"bank_alias":"大连普兰店汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005736"},{"bank_alias":"上海崇明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005737"},{"bank_alias":"浙江瑞安湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005738"},{"bank_alias":"庐山九银艺术村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005739"},{"bank_alias":"嘉祥中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005740"},{"bank_alias":"湖南洪江湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005741"},{"bank_alias":"昆明官渡沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005742"},{"bank_alias":"乌拉特前旗大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005743"},{"bank_alias":"宾阳北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005744"},{"bank_alias":"云南鹤庆渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005745"},{"bank_alias":"石柱中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005746"},{"bank_alias":"广西藤县桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005747"},{"bank_alias":"梅河口民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005748"},{"bank_alias":"沈丘中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005749"},{"bank_alias":"福建泉州台商投资区晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005750"},{"bank_alias":"湖北汉川农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005751"},{"bank_alias":"福建仙游瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005752"},{"bank_alias":"东莞大朗东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005754"},{"bank_alias":"沈阳沈北富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005756"},{"bank_alias":"新郑郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005757"},{"bank_alias":"南靖中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005758"},{"bank_alias":"安徽裕安盛平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005759"},{"bank_alias":"四川名山锦程村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005760"},{"bank_alias":"广西北流柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005761"},{"bank_alias":"呼和浩特市赛罕蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005763"},{"bank_alias":"大悟楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005764"},{"bank_alias":"望都中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005765"},{"bank_alias":"大方富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005766"},{"bank_alias":"重庆城口中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005768"},{"bank_alias":"瓮安富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005770"},{"bank_alias":"海林远东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005771"},{"bank_alias":"淄博淄川北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005772"},{"bank_alias":"巩义浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005773"},{"bank_alias":"桦南融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005774"},{"bank_alias":"宽城融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005775"},{"bank_alias":"武穴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005776"},{"bank_alias":"衡阳县沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005777"},{"bank_alias":"江苏泰兴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005778"},{"bank_alias":"山阴县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005780"},{"bank_alias":"铁岭新星村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005781"},{"bank_alias":"安新大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005782"},{"bank_alias":"嵩县兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005784"},{"bank_alias":"陕西榆林横山汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005785"},{"bank_alias":"阜平大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005786"},{"bank_alias":"房县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005787"},{"bank_alias":"曲阜中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005788"},{"bank_alias":"浮梁农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005789"},{"bank_alias":"宁乡沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005790"},{"bank_alias":"江门开平长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005791"},{"bank_alias":"枝江汉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005792"},{"bank_alias":"巴彦融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005793"},{"bank_alias":"阳谷沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005795"},{"bank_alias":"威县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005796"},{"bank_alias":"辽宁海城金海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005797"},{"bank_alias":"曲靖会泽长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005798"},{"bank_alias":"浙江兰溪越商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005799"},{"bank_alias":"四川仪陇惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005800"},{"bank_alias":"望谟富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005801"},{"bank_alias":"铜川印台恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005802"},{"bank_alias":"宁武县瑞都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005803"},{"bank_alias":"松原宁江惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005804"},{"bank_alias":"拜泉融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005805"},{"bank_alias":"沈阳法库富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005806"},{"bank_alias":"凉城县乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005807"},{"bank_alias":"南京六合九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005808"},{"bank_alias":"稷山县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005809"},{"bank_alias":"磐石吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005810"},{"bank_alias":"三亚惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005811"},{"bank_alias":"盘州万和村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005812"},{"bank_alias":"平阴蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005813"},{"bank_alias":"吉林丰满惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005814"},{"bank_alias":"代县泓都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005815"},{"bank_alias":"湖南桃江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005816"},{"bank_alias":"交口县融都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005817"},{"bank_alias":"安徽铜陵铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005818"},{"bank_alias":"柳河蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005819"},{"bank_alias":"哈尔滨幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005820"},{"bank_alias":"景德镇昌江九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005821"},{"bank_alias":"五常惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005822"},{"bank_alias":"平原圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005823"},{"bank_alias":"榆中浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005824"},{"bank_alias":"钟祥民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005825"},{"bank_alias":"宁夏贺兰回商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005826"},{"bank_alias":"乌海市乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005827"},{"bank_alias":"辽宁桓仁锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005828"},{"bank_alias":"开原象牙山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005829"},{"bank_alias":"安徽寿县联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005830"},{"bank_alias":"五峰金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005831"},{"bank_alias":"通辽金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005832"},{"bank_alias":"和政神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005833"},{"bank_alias":"湖南江华新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005834"},{"bank_alias":"云南元江北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005835"},{"bank_alias":"扬州广陵中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005836"},{"bank_alias":"锦州太和锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005837"},{"bank_alias":"大理宾川长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005838"},{"bank_alias":"长顺富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005839"},{"bank_alias":"广西陆川柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005840"},{"bank_alias":"安徽明光民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005841"},{"bank_alias":"安徽巢湖扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005842"},{"bank_alias":"福建德化成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005843"},{"bank_alias":"道真中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005844"},{"bank_alias":"天水市秦安众信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005845"},{"bank_alias":"桦川融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005846"},{"bank_alias":"东乌珠穆沁农信开元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005849"},{"bank_alias":"陕西咸阳渭城汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005850"},{"bank_alias":"深圳光明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005851"},{"bank_alias":"兰州永登新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005852"},{"bank_alias":"内蒙古托克托立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005853"},{"bank_alias":"洮南惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005854"},{"bank_alias":"浙江景宁银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005855"},{"bank_alias":"台江富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005856"},{"bank_alias":"武宁恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005857"},{"bank_alias":"务川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005858"},{"bank_alias":"屏南刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005859"},{"bank_alias":"兰州七里河新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005860"},{"bank_alias":"宽甸百丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005861"},{"bank_alias":"云南西山北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005862"},{"bank_alias":"通城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005863"},{"bank_alias":"惠水恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005864"},{"bank_alias":"武夷山本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005865"},{"bank_alias":"安徽休宁大地村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005866"},{"bank_alias":"湖北嘉鱼吴江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005867"},{"bank_alias":"浙江嘉善联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005868"},{"bank_alias":"广州增城长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005869"},{"bank_alias":"岚县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005870"},{"bank_alias":"烟台福山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005871"},{"bank_alias":"柘荣刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005872"},{"bank_alias":"山东沂南蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005873"},{"bank_alias":"青岛崂山交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005875"},{"bank_alias":"垣曲县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005876"},{"bank_alias":"广西横县桂商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005877"},{"bank_alias":"廊坊开发区融商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005878"},{"bank_alias":"浙江丽水莲都中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005879"},{"bank_alias":"莱芜珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005880"},{"bank_alias":"登封齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005881"},{"bank_alias":"岑溪市北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005882"},{"bank_alias":"彭山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005883"},{"bank_alias":"文山砚山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005884"},{"bank_alias":"安徽凤阳利民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005885"},{"bank_alias":"陕西陇县长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005887"},{"bank_alias":"浙江泰顺温银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005888"},{"bank_alias":"乳山天骄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005889"},{"bank_alias":"毕节发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005890"},{"bank_alias":"中山东凤珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005891"},{"bank_alias":"福建将乐成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005893"},{"bank_alias":"陕西太白长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005894"},{"bank_alias":"安溪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005895"},{"bank_alias":"浙江萧山湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005896"},{"bank_alias":"宁波江北富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005897"},{"bank_alias":"福建永春漳农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005898"},{"bank_alias":"陵水惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005899"},{"bank_alias":"民勤融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005900"},{"bank_alias":"阜康津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005901"},{"bank_alias":"白山浑江恒泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005902"},{"bank_alias":"中卫香山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005903"},{"bank_alias":"沧县吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005904"},{"bank_alias":"石嘴山市大武口石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005905"},{"bank_alias":"江苏沭阳东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005906"},{"bank_alias":"湖南衡山潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005907"},{"bank_alias":"蓬莱民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005908"},{"bank_alias":"浙江秀洲德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005909"},{"bank_alias":"温县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005910"},{"bank_alias":"中阳县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005911"},{"bank_alias":"郧西楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005912"},{"bank_alias":"无棣中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005913"},{"bank_alias":"腾冲民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005914"},{"bank_alias":"河南方城凤裕村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005915"},{"bank_alias":"呼和浩特市新城蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005916"},{"bank_alias":"福建尤溪成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005918"},{"bank_alias":"上海青浦惠金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005920"},{"bank_alias":"日照沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005921"},{"bank_alias":"上海浦东恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005922"},{"bank_alias":"重庆丰都汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005923"},{"bank_alias":"来安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005924"},{"bank_alias":"浙江常山联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005925"},{"bank_alias":"苏州吴中珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005926"},{"bank_alias":"金寨徽银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005927"},{"bank_alias":"怀仁县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005928"},{"bank_alias":"临猗县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005929"},{"bank_alias":"辽源龙山榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005930"},{"bank_alias":"武胜中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005931"},{"bank_alias":"西昌金信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005932"},{"bank_alias":"阿拉尔津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005933"},{"bank_alias":"都江堰金都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005934"},{"bank_alias":"平凉崆峒融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005935"},{"bank_alias":"抚松榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005936"},{"bank_alias":"永新庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005937"},{"bank_alias":"梅州客家村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005938"},{"bank_alias":"大理巍山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005939"},{"bank_alias":"临洮县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005940"},{"bank_alias":"临汾市尧都区惠都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005941"},{"bank_alias":"宁波慈溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005943"},{"bank_alias":"福建连江恒欣村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005944"},{"bank_alias":"东莞常平新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005945"},{"bank_alias":"广西平南桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005946"},{"bank_alias":"福建长乐泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005947"},{"bank_alias":"饶阳民商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005948"},{"bank_alias":"宜兴阳羡村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005950"},{"bank_alias":"蓝田中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005951"},{"bank_alias":"集安惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005952"},{"bank_alias":"项城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005953"},{"bank_alias":"大邑交银兴民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005954"},{"bank_alias":"五华惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005955"},{"bank_alias":"聊城沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005957"},{"bank_alias":"昭通昭阳富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005959"},{"bank_alias":"福建建阳瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005960"},{"bank_alias":"吉林龙潭华益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005961"},{"bank_alias":"陕西三原海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005962"},{"bank_alias":"朝阳柳城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005964"},{"bank_alias":"西双版纳勐海长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005965"},{"bank_alias":"富锦幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005966"},{"bank_alias":"德兴蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005967"},{"bank_alias":"福建福清泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005968"},{"bank_alias":"吉水庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005969"},{"bank_alias":"青岛即墨惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005970"},{"bank_alias":"萍乡湘东黄海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005971"},{"bank_alias":"大连甘井子浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005972"},{"bank_alias":"深圳龙华新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005973"},{"bank_alias":"曲靖富源富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005974"},{"bank_alias":"重庆巫溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005975"},{"bank_alias":"天镇县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005976"},{"bank_alias":"武城圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005977"},{"bank_alias":"沙洋中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005978"},{"bank_alias":"昆明晋宁融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005979"},{"bank_alias":"辽源西安区榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005980"},{"bank_alias":"奇台利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005981"},{"bank_alias":"北京门头沟珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005982"},{"bank_alias":"崇仁九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005983"},{"bank_alias":"安平惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005984"},{"bank_alias":"东莞虎门长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005985"},{"bank_alias":"万州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005986"},{"bank_alias":"金沙富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005987"},{"bank_alias":"百色右江华润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005988"},{"bank_alias":"邹平浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005989"},{"bank_alias":"行唐利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005990"},{"bank_alias":"广汉珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005991"},{"bank_alias":"福建蕉城刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005992"},{"bank_alias":"从江月明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005993"},{"bank_alias":"阜南中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005994"},{"bank_alias":"慈利沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005995"},{"bank_alias":"文昌大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005997"},{"bank_alias":"广西桂平桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005998"},{"bank_alias":"北京大兴九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006001"},{"bank_alias":"青海乐都三江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006002"},{"bank_alias":"双峰沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006003"},{"bank_alias":"重庆巴南浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006004"},{"bank_alias":"日照九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006005"},{"bank_alias":"寿光张农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006006"},{"bank_alias":"辉县珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006007"},{"bank_alias":"泰州姜堰锡州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006008"},{"bank_alias":"湖北荆门掇刀包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006009"},{"bank_alias":"广东英德泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006010"},{"bank_alias":"晋中市左权华丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006011"},{"bank_alias":"思南长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006012"},{"bank_alias":"旬邑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006013"},{"bank_alias":"巴彦淖尔市临河黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006014"},{"bank_alias":"浙江义乌联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006015"},{"bank_alias":"浙江文成北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006016"},{"bank_alias":"浙江玉环永兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006017"},{"bank_alias":"富蕴中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006019"},{"bank_alias":"杭锦大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006020"},{"bank_alias":"上海松江民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006021"},{"bank_alias":"重庆涪陵中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006023"},{"bank_alias":"忻州市忻府区秀都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006024"},{"bank_alias":"巴中中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006025"},{"bank_alias":"东莞长安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006026"},{"bank_alias":"宿迁宿城兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006027"},{"bank_alias":"伊金霍洛金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006029"},{"bank_alias":"河南叶县泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006030"},{"bank_alias":"湖口九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006031"},{"bank_alias":"海阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006033"},{"bank_alias":"河间融惠村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006034"},{"bank_alias":"无锡滨湖兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006035"},{"bank_alias":"浙江新昌浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006036"},{"bank_alias":"潜江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006037"},{"bank_alias":"陕西洛南阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006038"},{"bank_alias":"湖南平江汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006039"},{"bank_alias":"湖南中方新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006040"},{"bank_alias":"合阳惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006041"},{"bank_alias":"青原庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006042"},{"bank_alias":"莒县金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006043"},{"bank_alias":"黎川抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006044"},{"bank_alias":"江苏启东珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006045"},{"bank_alias":"通许融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006046"},{"bank_alias":"成安齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006047"},{"bank_alias":"福建南安汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006048"},{"bank_alias":"韩城浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006049"},{"bank_alias":"哈尔滨宾洲村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006050"},{"bank_alias":"弋阳蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006051"},{"bank_alias":"福建泰宁晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006052"},{"bank_alias":"杜尔伯特润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006053"},{"bank_alias":"本溪禾丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006054"},{"bank_alias":"竹溪楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006055"},{"bank_alias":"孝昌本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006056"},{"bank_alias":"天津市北辰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006057"},{"bank_alias":"伊金霍洛六菱村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006058"},{"bank_alias":"云南石屏北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006059"},{"bank_alias":"铜鼓九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006061"},{"bank_alias":"宁夏同心津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006062"},{"bank_alias":"宁夏西夏贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006063"},{"bank_alias":"保定满城区利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006064"},{"bank_alias":"安徽濉溪湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006065"},{"bank_alias":"安徽肥东湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006066"},{"bank_alias":"定陶河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006067"},{"bank_alias":"建平红山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006068"},{"bank_alias":"山东郯城汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006069"},{"bank_alias":"哈密天山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006070"},{"bank_alias":"井冈山九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006071"},{"bank_alias":"重庆忠县稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006072"},{"bank_alias":"奉节中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006073"},{"bank_alias":"贵溪九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006074"},{"bank_alias":"宁海中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006075"},{"bank_alias":"松滋中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006076"},{"bank_alias":"上海宝山扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006077"},{"bank_alias":"新密郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006078"},{"bank_alias":"镇赉中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006080"},{"bank_alias":"浙江桐庐恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006081"},{"bank_alias":"滦州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006082"},{"bank_alias":"独山富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006084"},{"bank_alias":"北票盛都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006085"},{"bank_alias":"重庆南川石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006087"},{"bank_alias":"安徽桐城江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006088"},{"bank_alias":"山东成武汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006090"},{"bank_alias":"壶关县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006091"},{"bank_alias":"沈阳辽中富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006092"},{"bank_alias":"阜宁民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006093"},{"bank_alias":"上海金山惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006094"},{"bank_alias":"临武浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006095"},{"bank_alias":"临邑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006096"},{"bank_alias":"信阳平桥中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006097"},{"bank_alias":"恩施兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006098"},{"bank_alias":"鹰潭月湖恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006099"},{"bank_alias":"江苏新沂汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006100"},{"bank_alias":"雅安雨城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006101"},{"bank_alias":"东港同合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006102"},{"bank_alias":"广西容县桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006103"},{"bank_alias":"葫芦岛国信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006104"},{"bank_alias":"灵宝融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006105"},{"bank_alias":"阜城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006106"},{"bank_alias":"罗平兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006107"},{"bank_alias":"安徽繁昌中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006108"},{"bank_alias":"宁夏红寺堡汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006109"},{"bank_alias":"宜昌夷陵兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006110"},{"bank_alias":"海伦惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006111"},{"bank_alias":"公主岭浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006112"},{"bank_alias":"沂水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006113"},{"bank_alias":"海南白沙长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006114"},{"bank_alias":"祁阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006115"},{"bank_alias":"昆明呈贡华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006116"},{"bank_alias":"山东邹城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006117"},{"bank_alias":"应城融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006118"},{"bank_alias":"东营河口中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006119"},{"bank_alias":"保定清苑区邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006120"},{"bank_alias":"克山润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006121"},{"bank_alias":"南丰桔都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006122"},{"bank_alias":"浠水楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006123"},{"bank_alias":"兴城长兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006124"},{"bank_alias":"湖北红安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006125"},{"bank_alias":"长宁中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006126"},{"bank_alias":"卓资蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006127"},{"bank_alias":"崇阳楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006128"},{"bank_alias":"潍坊市寒亭区蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006129"},{"bank_alias":"三河蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006130"},{"bank_alias":"安徽徽州铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006131"},{"bank_alias":"莱芜中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006132"},{"bank_alias":"资溪九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006133"},{"bank_alias":"浙江安吉交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006135"},{"bank_alias":"安徽蒙城湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006137"},{"bank_alias":"涟源沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006138"},{"bank_alias":"邯郸邯山齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006139"},{"bank_alias":"河南栾川民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006140"},{"bank_alias":"贵阳观山湖富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006141"},{"bank_alias":"百色靖西长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006142"},{"bank_alias":"吉州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006143"},{"bank_alias":"山东梁山民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006144"},{"bank_alias":"赤峰市松山立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006145"},{"bank_alias":"广西博白柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006146"},{"bank_alias":"三水珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006147"},{"bank_alias":"合川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006148"},{"bank_alias":"辉南榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006151"},{"bank_alias":"凤翔中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006153"},{"bank_alias":"江苏泗阳东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006154"},{"bank_alias":"翁牛特立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006155"},{"bank_alias":"城固中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006157"},{"bank_alias":"曲靖宣威长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006158"},{"bank_alias":"安徽舒城正兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006159"},{"bank_alias":"长春高新惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006160"},{"bank_alias":"颍上中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006161"},{"bank_alias":"随县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006162"},{"bank_alias":"苍梧深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006163"},{"bank_alias":"九江恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006164"},{"bank_alias":"安图农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006165"},{"bank_alias":"杭锦后旗河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006167"},{"bank_alias":"吴忠市滨河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006168"},{"bank_alias":"黄平振兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006169"},{"bank_alias":"江苏盱眙珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006170"},{"bank_alias":"福建宁化成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006171"},{"bank_alias":"新疆建新成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006172"},{"bank_alias":"浙江苍南中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006173"},{"bank_alias":"罗甸发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006174"},{"bank_alias":"清镇兴邦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006175"},{"bank_alias":"广西融水柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006176"},{"bank_alias":"孟村回族自治县融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006177"},{"bank_alias":"郏县广天村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006178"},{"bank_alias":"遂平中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006179"},{"bank_alias":"石门沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006180"},{"bank_alias":"江苏洪泽金阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006181"},{"bank_alias":"南华兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006182"},{"bank_alias":"海南琼中长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006183"},{"bank_alias":"云安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006184"},{"bank_alias":"长岭蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006185"},{"bank_alias":"广饶梁邹村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006186"},{"bank_alias":"景洪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006188"},{"bank_alias":"吴江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006189"},{"bank_alias":"樟树顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006190"},{"bank_alias":"安徽潜山江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006192"},{"bank_alias":"承德县恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006193"},{"bank_alias":"浙江上虞富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006194"},{"bank_alias":"安徽定远民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006195"},{"bank_alias":"昌邑北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006196"},{"bank_alias":"鄱阳恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006197"},{"bank_alias":"大同市南郊区京都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006198"},{"bank_alias":"大理古城中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006199"},{"bank_alias":"卢氏中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006200"},{"bank_alias":"郓城北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006201"},{"bank_alias":"丹东鼎安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006202"},{"bank_alias":"太和中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006203"},{"bank_alias":"田东北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006204"},{"bank_alias":"浙江磐安婺商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006206"},{"bank_alias":"重庆秀山北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006207"},{"bank_alias":"志丹民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006209"},{"bank_alias":"上杭中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006210"},{"bank_alias":"安徽灵璧本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006211"},{"bank_alias":"汾西县亿通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006212"},{"bank_alias":"普安普惠村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006213"},{"bank_alias":"修水九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006214"},{"bank_alias":"佛山高明顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006215"},{"bank_alias":"河津市龙都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006216"},{"bank_alias":"福建永定瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006217"},{"bank_alias":"日照蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006218"},{"bank_alias":"曲沃县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006219"},{"bank_alias":"重庆荣昌汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006220"},{"bank_alias":"睢宁中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006221"},{"bank_alias":"深圳罗湖蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006222"},{"bank_alias":"尉氏合益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006223"},{"bank_alias":"海南昌江长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006224"},{"bank_alias":"临颍中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006225"},{"bank_alias":"江苏高淳武家嘴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006226"},{"bank_alias":"定州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006227"},{"bank_alias":"魏县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006228"},{"bank_alias":"通化东昌榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006230"},{"bank_alias":"鹿泉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006231"},{"bank_alias":"临沂河东齐商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006232"},{"bank_alias":"临川浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006233"},{"bank_alias":"辛集齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006234"},{"bank_alias":"玉溪澄江中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006235"},{"bank_alias":"金堂汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006236"},{"bank_alias":"哈尔滨呼兰浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006237"},{"bank_alias":"湖南洞口潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006238"},{"bank_alias":"长葛轩辕村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006239"},{"bank_alias":"福建闽清瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006240"},{"bank_alias":"新乡中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006242"},{"bank_alias":"江苏溧水民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006243"},{"bank_alias":"瑞丽沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006244"},{"bank_alias":"湖南攸县潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006245"},{"bank_alias":"兴县汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006246"},{"bank_alias":"新都桂城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006247"},{"bank_alias":"重庆大足汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006248"},{"bank_alias":"浙江台州黄岩恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006249"},{"bank_alias":"乐陵圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006250"},{"bank_alias":"阿拉善左旗黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006251"},{"bank_alias":"安徽霍山联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006252"},{"bank_alias":"土默特左旗金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006253"},{"bank_alias":"辽宁义县锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006254"},{"bank_alias":"浙江德清湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006255"},{"bank_alias":"达拉特中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006256"},{"bank_alias":"海南儋州绿色村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006257"},{"bank_alias":"玉屏长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006258"},{"bank_alias":"宁波海曙浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006260"},{"bank_alias":"兴义万丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006261"},{"bank_alias":"象山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006262"},{"bank_alias":"安徽五河永泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006263"},{"bank_alias":"建湖中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006264"},{"bank_alias":"江苏靖江润丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006265"},{"bank_alias":"清徐惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006266"},{"bank_alias":"嫩江幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006267"},{"bank_alias":"临江蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006268"},{"bank_alias":"安徽谯城湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006269"},{"bank_alias":"陕西周至农科村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006270"},{"bank_alias":"九台龙嘉村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006271"},{"bank_alias":"来宾象州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006272"},{"bank_alias":"福建漳平民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006273"},{"bank_alias":"山东商河汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006275"},{"bank_alias":"福建福鼎恒兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006276"},{"bank_alias":"常州新北中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006277"},{"bank_alias":"汕头龙湖长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006278"},{"bank_alias":"宁夏永宁汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006280"},{"bank_alias":"元谋兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006281"},{"bank_alias":"深州丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006282"},{"bank_alias":"安徽岳西湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006283"},{"bank_alias":"张家口崇礼邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006284"},{"bank_alias":"余干恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006285"},{"bank_alias":"鄯善中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006286"},{"bank_alias":"蒙自沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006287"},{"bank_alias":"德庆华润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006288"},{"bank_alias":"河南沁阳江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006289"},{"bank_alias":"彭泽九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006290"},{"bank_alias":"保山昌宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006291"},{"bank_alias":"单县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006292"},{"bank_alias":"文山富宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006293"},{"bank_alias":"青海平安大通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006294"},{"bank_alias":"开鲁蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006295"},{"bank_alias":"湖北公安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006297"},{"bank_alias":"天津武清村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006298"},{"bank_alias":"宣汉诚民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006299"},{"bank_alias":"全椒中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006300"},{"bank_alias":"济宁蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006301"},{"bank_alias":"陕西岐山长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006302"},{"bank_alias":"南和融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006303"},{"bank_alias":"雄县丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006304"},{"bank_alias":"天津静海新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006305"},{"bank_alias":"响水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006306"},{"bank_alias":"凌源天元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006307"},{"bank_alias":"福建武平杭兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006308"},{"bank_alias":"微山北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006309"},{"bank_alias":"青海门源大通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006310"},{"bank_alias":"湖北大冶泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006311"},{"bank_alias":"瑞昌九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006312"},{"bank_alias":"长垣民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006313"},{"bank_alias":"抚顺新宾抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006314"},{"bank_alias":"赫章富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006315"},{"bank_alias":"安义融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006316"},{"bank_alias":"章丘齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006317"},{"bank_alias":"江西婺源江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006318"},{"bank_alias":"陕西吴起汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006319"},{"bank_alias":"清远清新惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006320"},{"bank_alias":"哈尔滨农信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006321"},{"bank_alias":"陵川县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006322"},{"bank_alias":"汾阳市九都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006323"},{"bank_alias":"济源齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006324"},{"bank_alias":"江苏武进中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006325"},{"bank_alias":"衡水冀州丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006326"},{"bank_alias":"塔城津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006327"},{"bank_alias":"济宁儒商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006328"},{"bank_alias":"福建福安渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006329"},{"bank_alias":"湖南溆浦湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006330"},{"bank_alias":"扎赉特蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006331"},{"bank_alias":"庐江惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006332"},{"bank_alias":"保山隆阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006333"},{"bank_alias":"长汀汀州红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006334"},{"bank_alias":"本溪丰泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006335"},{"bank_alias":"广西兴业柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006336"},{"bank_alias":"南昌昌东九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006337"},{"bank_alias":"南京浦口靖发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006338"},{"bank_alias":"乾县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006339"},{"bank_alias":"靖安九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006340"},{"bank_alias":"密山民意村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006341"},{"bank_alias":"福建诏安汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006342"},{"bank_alias":"固始天骄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006343"},{"bank_alias":"唐山市开平汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006345"},{"bank_alias":"菏泽牡丹北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006346"},{"bank_alias":"武乡县泽都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006347"},{"bank_alias":"上海浦东江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006348"},{"bank_alias":"济南长清沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006349"},{"bank_alias":"柘城黄淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006350"},{"bank_alias":"武汉东西湖扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006351"},{"bank_alias":"中江融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006352"},{"bank_alias":"石家庄栾城齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006353"},{"bank_alias":"宜黄抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006354"},{"bank_alias":"青岛西海岸海汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006355"},{"bank_alias":"新疆石河子市交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006356"},{"bank_alias":"江苏张家港渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006357"},{"bank_alias":"安徽广德扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006359"},{"bank_alias":"兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006360"},{"bank_alias":"新余孔目江成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006362"},{"bank_alias":"湖南东安星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006363"},{"bank_alias":"镇江润州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006364"},{"bank_alias":"江苏邳州陇海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006365"},{"bank_alias":"丽江古城富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006366"},{"bank_alias":"漯河市郾城包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006367"},{"bank_alias":"盐城滨海兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006369"},{"bank_alias":"浑源县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006370"},{"bank_alias":"浙江江山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006371"},{"bank_alias":"安徽东至扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006372"},{"bank_alias":"沁源县长青村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006373"},{"bank_alias":"侯马市太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006374"},{"bank_alias":"剑河富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006375"},{"bank_alias":"昆明马金铺中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006376"},{"bank_alias":"上饶中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006377"},{"bank_alias":"余庆中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006378"},{"bank_alias":"南宁兴宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006379"},{"bank_alias":"昆明宜良融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006380"},{"bank_alias":"施秉金鼎村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006381"},{"bank_alias":"江西赣州银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006382"},{"bank_alias":"营口宏诚村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006383"},{"bank_alias":"中牟郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006384"},{"bank_alias":"长阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006385"},{"bank_alias":"曲靖惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006387"},{"bank_alias":"宁波奉化罗蒙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006388"},{"bank_alias":"宁波北仑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006389"},{"bank_alias":"黔西南义龙浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006390"},{"bank_alias":"石家庄新华恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006391"},{"bank_alias":"山东肥城民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006393"},{"bank_alias":"舒兰吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006394"},{"bank_alias":"永靖县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006395"},{"bank_alias":"兰西农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006396"},{"bank_alias":"天水秦州长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006397"},{"bank_alias":"河北丰宁中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006399"},{"bank_alias":"江西高安富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006400"},{"bank_alias":"扶沟郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006401"},{"bank_alias":"涿鹿利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006402"},{"bank_alias":"清徐晋商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006403"},{"bank_alias":"大通中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006404"},{"bank_alias":"常宁珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006405"},{"bank_alias":"昆明五华长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006407"},{"bank_alias":"重庆垫江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006408"},{"bank_alias":"万荣县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006409"},{"bank_alias":"普洱民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006410"},{"bank_alias":"介休市华都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006412"},{"bank_alias":"陕西旬阳泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006413"},{"bank_alias":"中山古镇南粤村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006416"},{"bank_alias":"上海松江富明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006417"},{"bank_alias":"澧县沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006418"},{"bank_alias":"桐梓中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006419"},{"bank_alias":"江西芦溪富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006420"},{"bank_alias":"荆门东宝惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006421"},{"bank_alias":"浙江衢州衢江上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006422"},{"bank_alias":"江西信州江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006424"},{"bank_alias":"宜丰中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006426"},{"bank_alias":"扎兰屯蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006427"},{"bank_alias":"滦平盛阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006428"},{"bank_alias":"淮安清浦兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006429"},{"bank_alias":"泌阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006430"},{"bank_alias":"灵石县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006431"},{"bank_alias":"宣化中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006432"},{"bank_alias":"宁安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006433"},{"bank_alias":"上海嘉定民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006434"},{"bank_alias":"浙江洞头富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006435"},{"bank_alias":"郧县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006436"},{"bank_alias":"茶陵浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006437"},{"bank_alias":"团风楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006439"},{"bank_alias":"开阳富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006440"},{"bank_alias":"潮州潮安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006441"},{"bank_alias":"浙江建德湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006442"},{"bank_alias":"习水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006443"},{"bank_alias":"江苏淮安光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006444"},{"bank_alias":"山东新泰齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006445"},{"bank_alias":"蔚县银泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006446"},{"bank_alias":"惠州博罗长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006447"},{"bank_alias":"南昌大丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006448"},{"bank_alias":"广州白云民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006450"},{"bank_alias":"临县泉都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006452"},{"bank_alias":"云浮新兴东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006453"},{"bank_alias":"周宁刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006454"},{"bank_alias":"嵩明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006455"},{"bank_alias":"德惠敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006456"},{"bank_alias":"榆林榆阳民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006457"},{"bank_alias":"包头市昆都仑蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006458"},{"bank_alias":"印江长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006459"},{"bank_alias":"湖南湘潭湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006460"},{"bank_alias":"白城洮北惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006461"},{"bank_alias":"仁寿民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006462"},{"bank_alias":"惠州仲恺东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006464"},{"bank_alias":"东山润鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006465"},{"bank_alias":"福建大田晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006466"},{"bank_alias":"寿阳县汇都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006467"},{"bank_alias":"海口苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006468"},{"bank_alias":"上海宝山富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006470"},{"bank_alias":"灵川深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006471"},{"bank_alias":"鄂托克旗汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006472"},{"bank_alias":"泸水中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006473"},{"bank_alias":"张北信达村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006474"},{"bank_alias":"蕲春中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006478"},{"bank_alias":"云梦楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006479"},{"bank_alias":"柏乡融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006480"},{"bank_alias":"安塞农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006481"},{"bank_alias":"陕西柞水聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006483"},{"bank_alias":"许昌新浦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006484"},{"bank_alias":"大连金州联丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006485"},{"bank_alias":"江苏涟水太商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006486"},{"bank_alias":"宜都民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006487"},{"bank_alias":"深圳龙岗中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006488"},{"bank_alias":"阆中融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006489"},{"bank_alias":"神池县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006490"},{"bank_alias":"内黄兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006491"},{"bank_alias":"怀来利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006493"},{"bank_alias":"甘肃西固金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006494"},{"bank_alias":"江川兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006495"},{"bank_alias":"临沭民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006496"},{"bank_alias":"延吉和润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006497"},{"bank_alias":"江苏邗江联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006498"},{"bank_alias":"湖北随州曾都汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006499"},{"bank_alias":"兰州皋兰新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006500"},{"bank_alias":"桦甸惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006501"},{"bank_alias":"巴彦淖尔市乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006502"},{"bank_alias":"普定富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006503"},{"bank_alias":"兴平中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006504"},{"bank_alias":"乐安洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006505"},{"bank_alias":"常州钟楼长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006507"},{"bank_alias":"农安北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006508"},{"bank_alias":"宁陵德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006509"},{"bank_alias":"汪清和润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006510"},{"bank_alias":"文山丘北长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006511"},{"bank_alias":"北京密云汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006512"},{"bank_alias":"湖北英山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006513"},{"bank_alias":"岳池中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006514"},{"bank_alias":"陕西泾阳泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006515"},{"bank_alias":"分宜九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006516"},{"bank_alias":"龙井榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006517"},{"bank_alias":"慈溪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006518"},{"bank_alias":"卫辉富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006519"},{"bank_alias":"河南新野中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006520"},{"bank_alias":"平罗沙湖村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006521"},{"bank_alias":"曹县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006522"},{"bank_alias":"济南高新北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006523"},{"bank_alias":"织金惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006524"},{"bank_alias":"永寿中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006525"},{"bank_alias":"福建建瓯瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006526"},{"bank_alias":"荔波富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006527"},{"bank_alias":"建水沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006528"},{"bank_alias":"贵阳南明富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006529"},{"bank_alias":"长春绿园融泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006530"},{"bank_alias":"古交市汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006531"},{"bank_alias":"新绛县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006532"},{"bank_alias":"浙江云和联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006533"},{"bank_alias":"玉田大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006534"},{"bank_alias":"什邡思源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006535"},{"bank_alias":"湖南沅陵新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006536"},{"bank_alias":"东辽农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006537"},{"bank_alias":"汝州玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006538"},{"bank_alias":"陕西户县海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006539"},{"bank_alias":"筠连中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006540"},{"bank_alias":"德宏芒市长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006541"},{"bank_alias":"四平辽河蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006542"},{"bank_alias":"平塘富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006543"},{"bank_alias":"曲靖沾益兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006544"},{"bank_alias":"辽宁彰武金通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006545"},{"bank_alias":"淳化中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006547"},{"bank_alias":"汤阴兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006548"},{"bank_alias":"柳林汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006549"},{"bank_alias":"都昌九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006550"},{"bank_alias":"民权德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006551"},{"bank_alias":"青岛平度惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006552"},{"bank_alias":"隆德六盘山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006553"},{"bank_alias":"湖南宁远潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006555"},{"bank_alias":"阳新汉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006556"},{"bank_alias":"武隆融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006557"},{"bank_alias":"上海浦东中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006558"},{"bank_alias":"浙江东阳富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006559"},{"bank_alias":"安徽郎溪新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006560"},{"bank_alias":"昆明禄劝中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006561"},{"bank_alias":"文安县惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006562"},{"bank_alias":"汾西县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006563"},{"bank_alias":"安徽黄山金桥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006564"},{"bank_alias":"襄汾县万都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006565"},{"bank_alias":"霍林郭勒蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006566"},{"bank_alias":"乌海千里山河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006568"},{"bank_alias":"宁夏宁东本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006569"},{"bank_alias":"赤城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006570"},{"bank_alias":"磴口蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006571"},{"bank_alias":"北京顺义银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006572"},{"bank_alias":"安徽怀远本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006573"},{"bank_alias":"山东泗水齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006574"},{"bank_alias":"包头市东河金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006575"},{"bank_alias":"正安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006576"},{"bank_alias":"江西瑞金光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006577"},{"bank_alias":"辽宁首山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006578"},{"bank_alias":"黑龙江肇东中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006579"},{"bank_alias":"晋州恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006580"},{"bank_alias":"永吉吉庆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006581"},{"bank_alias":"浙江龙游义商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006582"},{"bank_alias":"南城富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006584"},{"bank_alias":"宜章长行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006586"},{"bank_alias":"寻甸中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006587"},{"bank_alias":"田阳兴阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006588"},{"bank_alias":"包头青山河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006589"},{"bank_alias":"山东蒙阴齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006590"},{"bank_alias":"犍为中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006591"},{"bank_alias":"湖南桃源湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006592"},{"bank_alias":"广丰广信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006593"},{"bank_alias":"赞皇隆兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006594"},{"bank_alias":"迁安襄隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006595"},{"bank_alias":"峡江洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006596"},{"bank_alias":"泽州浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006597"},{"bank_alias":"福建龙海泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006598"},{"bank_alias":"珲春吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006600"},{"bank_alias":"青岛胶州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006601"},{"bank_alias":"青州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006602"},{"bank_alias":"中山小榄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006603"},{"bank_alias":"江苏通州华商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006604"},{"bank_alias":"广西柳江柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006605"},{"bank_alias":"陆良兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006606"},{"bank_alias":"浙江岱山稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006607"},{"bank_alias":"浙江温岭联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006608"},{"bank_alias":"凤城丰益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006610"},{"bank_alias":"浙江嵊州瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006611"},{"bank_alias":"扶绥深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006612"},{"bank_alias":"武邑邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006613"},{"bank_alias":"湖北咸安武农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006614"},{"bank_alias":"山东滕州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006615"},{"bank_alias":"信阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006617"},{"bank_alias":"安徽当涂新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006618"},{"bank_alias":"修文江海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006619"},{"bank_alias":"宁晋民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006620"},{"bank_alias":"白银平川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006622"},{"bank_alias":"安国中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006623"},{"bank_alias":"安徽金寨江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006624"},{"bank_alias":"乾安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006625"},{"bank_alias":"陕西眉县泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006626"},{"bank_alias":"隰县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006627"},{"bank_alias":"江苏如东融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006628"},{"bank_alias":"鄂尔多斯市罕台村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006629"},{"bank_alias":"长白榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006630"},{"bank_alias":"宝清广益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006631"},{"bank_alias":"淮阳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006632"},{"bank_alias":"深圳南山宝生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006633"},{"bank_alias":"福建连城杭兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006635"},{"bank_alias":"高平市太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006637"},{"bank_alias":"九江庐山浔银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006638"},{"bank_alias":"安徽泾县铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006639"},{"bank_alias":"江苏邗江民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006640"},{"bank_alias":"宜宾兴宜村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006641"},{"bank_alias":"湘西长行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006642"},{"bank_alias":"扬州高邮兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006643"},{"bank_alias":"六盘水六枝富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006644"},{"bank_alias":"银川掌政石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006645"},{"bank_alias":"渑池齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006646"},{"bank_alias":"重庆江津石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006647"},{"bank_alias":"宁阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006648"},{"bank_alias":"重庆渝北银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006649"},{"bank_alias":"沈阳康平抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006650"},{"bank_alias":"高密惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006651"},{"bank_alias":"潍坊市潍城区北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006652"},{"bank_alias":"宁夏平罗县沙湖村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006653"},{"bank_alias":"安徽宣州湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006654"},{"bank_alias":"湖北天门汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006655"},{"bank_alias":"抚顺顺城抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006656"},{"bank_alias":"江苏惠山民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006657"},{"bank_alias":"江西莲花富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006658"},{"bank_alias":"建昌恒昌村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006659"},{"bank_alias":"新余渝水湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006660"},{"bank_alias":"宜阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006661"},{"bank_alias":"禄丰龙城富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006662"},{"bank_alias":"邻水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006664"},{"bank_alias":"永丰洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006665"},{"bank_alias":"奉新九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006666"},{"bank_alias":"山东冠县齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006667"},{"bank_alias":"青岛黄岛舜丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006668"},{"bank_alias":"遂川洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006669"},{"bank_alias":"贵阳花溪建设村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006670"},{"bank_alias":"阳曲县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006672"},{"bank_alias":"湄潭中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006674"},{"bank_alias":"辽宁黑山锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006675"},{"bank_alias":"丽江永胜长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006676"},{"bank_alias":"文山广南长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006677"},{"bank_alias":"定兴丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006678"},{"bank_alias":"琼海大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006679"},{"bank_alias":"成都青白江融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006680"},{"bank_alias":"广昌南银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006682"},{"bank_alias":"涞水利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006683"},{"bank_alias":"湖南汉寿星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006684"},{"bank_alias":"玉山三清山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006685"},{"bank_alias":"湖南衡东新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006686"},{"bank_alias":"重庆市酉阳融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006687"},{"bank_alias":"浦城中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006688"},{"bank_alias":"尉犁达西冀银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006689"},{"bank_alias":"原平市汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006690"},{"bank_alias":"汉中汉台铺镇聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006691"},{"bank_alias":"珠海南屏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006692"},{"bank_alias":"贵阳乌当富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006693"},{"bank_alias":"凤冈中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006694"},{"bank_alias":"江门新会新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006695"},{"bank_alias":"塔城昆仑村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006696"},{"bank_alias":"安达幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006697"},{"bank_alias":"赤峰市红山玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006698"},{"bank_alias":"古交市阜民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006699"},{"bank_alias":"孟州射阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006700"},{"bank_alias":"山东招远中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006701"},{"bank_alias":"浙江柯桥联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006702"},{"bank_alias":"江苏赣榆通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006703"},{"bank_alias":"涿州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006704"},{"bank_alias":"广州从化柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006705"},{"bank_alias":"朔州市朔城区蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006707"},{"bank_alias":"江苏射阳太商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006708"},{"bank_alias":"重庆梁平澳新村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006709"},{"bank_alias":"集贤润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006712"},{"bank_alias":"江陵楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006713"},{"bank_alias":"新疆库尔勒富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006714"},{"bank_alias":"兴宁珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006715"},{"bank_alias":"平山西柏坡冀银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006716"},{"bank_alias":"陕西临潼海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006717"},{"bank_alias":"江苏铜山锡州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006718"},{"bank_alias":"天水麦积融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006719"},{"bank_alias":"海南澄迈长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006720"},{"bank_alias":"海南屯昌长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006721"},{"bank_alias":"吴桥融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006723"},{"bank_alias":"丹东鼎元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006724"},{"bank_alias":"昆明东川中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006725"},{"bank_alias":"青海湟中三江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006726"},{"bank_alias":"长武中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006727"},{"bank_alias":"浙江临安中信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006728"},{"bank_alias":"兖州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006729"},{"bank_alias":"重庆永川北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006731"},{"bank_alias":"吉林船营惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006732"},{"bank_alias":"宜州深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006734"},{"bank_alias":"伊通榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006735"},{"bank_alias":"安顺西秀富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006736"},{"bank_alias":"浙江乐清联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006738"},{"bank_alias":"江阴浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006739"},{"bank_alias":"合水县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006740"},{"bank_alias":"芜湖圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006741"},{"bank_alias":"北京房山沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006742"},{"bank_alias":"湖南蓝山神农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006743"},{"bank_alias":"阳高县兴都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006744"},{"bank_alias":"安陆楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006745"},{"bank_alias":"江苏宝应锦程村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006746"},{"bank_alias":"重庆九龙坡民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006747"},{"bank_alias":"北京平谷新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006748"},{"bank_alias":"平陆县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006749"},{"bank_alias":"淄博博山北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006750"},{"bank_alias":"山东荣成汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006751"},{"bank_alias":"蒲城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006752"},{"bank_alias":"洪洞县洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006754"},{"bank_alias":"乐亭舜丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006755"},{"bank_alias":"东莞厚街华业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006756"},{"bank_alias":"龙里国丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006757"},{"bank_alias":"江苏海安盐海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006758"},{"bank_alias":"安徽宿州淮海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006760"},{"bank_alias":"大冶中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006761"},{"bank_alias":"佛山南海新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006765"},{"bank_alias":"故城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006766"},{"bank_alias":"安徽石台扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006767"},{"bank_alias":"潍坊市奎文区中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006768"},{"bank_alias":"广安恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006769"},{"bank_alias":"楚雄红塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006770"},{"bank_alias":"丹东福汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006771"},{"bank_alias":"常州金坛兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006772"},{"bank_alias":"辽宁沈东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006773"},{"bank_alias":"广州黄埔惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006774"},{"bank_alias":"建宁刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006775"},{"bank_alias":"靖宇乾丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006776"},{"bank_alias":"崇左大新长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006777"},{"bank_alias":"太仆寺旗鑫源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006778"},{"bank_alias":"江苏沛县汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006779"},{"bank_alias":"和龙敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006780"},{"bank_alias":"宁国民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006781"},{"bank_alias":"宁波镇海中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006782"},{"bank_alias":"广元市贵商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006783"},{"bank_alias":"滨州河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006784"},{"bank_alias":"包头市九原立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006785"},{"bank_alias":"宁夏青铜峡贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006786"},{"bank_alias":"江苏东台稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006787"},{"bank_alias":"应县金都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006788"},{"bank_alias":"广东四会泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006789"},{"bank_alias":"鄂尔多斯市东胜蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006790"},{"bank_alias":"安徽和县新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006792"},{"bank_alias":"宜城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006794"},{"bank_alias":"深圳宝安桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006795"},{"bank_alias":"绥中长丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006796"},{"bank_alias":"辽宁千山金泉村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006797"},{"bank_alias":"巨野中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006799"},{"bank_alias":"长沙星沙沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006800"},{"bank_alias":"梨树源泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006801"},{"bank_alias":"呼和浩特市如意蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006802"},{"bank_alias":"天津西青中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006803"},{"bank_alias":"丹江口楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006804"},{"bank_alias":"淇县中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006805"},{"bank_alias":"呼和浩特金桥河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006807"},{"bank_alias":"天津津南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006808"},{"bank_alias":"永修浔银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006809"},{"bank_alias":"景县丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006810"},{"bank_alias":"虞城通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006811"},{"bank_alias":"雷州惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006812"},{"bank_alias":"沅江浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006813"},{"bank_alias":"濮阳中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006814"},{"bank_alias":"乌拉特中旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006815"},{"bank_alias":"南宁马山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006818"},{"bank_alias":"东平沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006820"},{"bank_alias":"闻喜县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006821"},{"bank_alias":"大连旅顺口蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006822"},{"bank_alias":"汝阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006823"},{"bank_alias":"大连保税区珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006824"},{"bank_alias":"南部县中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006825"},{"bank_alias":"扶余惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006826"},{"bank_alias":"重庆南岸中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006827"},{"bank_alias":"鄂托克兴生源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006828"},{"bank_alias":"孟津民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006830"},{"bank_alias":"东莞黄江珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006831"},{"bank_alias":"陇西神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006832"},{"bank_alias":"山东诸城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006833"},{"bank_alias":"兴山本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006834"},{"bank_alias":"安徽歙县嘉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006835"},{"bank_alias":"都匀融通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006836"},{"bank_alias":"天津滨海扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006837"},{"bank_alias":"株洲县融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006838"},{"bank_alias":"沧州盐山新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006839"},{"bank_alias":"舞阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006840"},{"bank_alias":"天津滨海惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006842"},{"bank_alias":"重庆市大渡口融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006843"},{"bank_alias":"重庆市武隆融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006844"},{"bank_alias":"西安雁塔恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006845"},{"bank_alias":"阿拉善左旗方大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006846"},{"bank_alias":"遂宁安居融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006847"},{"bank_alias":"安康汉滨中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006848"},{"bank_alias":"四川北川羌族自治县富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006849"},{"bank_alias":"浚县郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006850"},{"bank_alias":"南陵太平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006851"},{"bank_alias":"广西兴安民兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006852"},{"bank_alias":"山东金乡蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006853"},{"bank_alias":"四川成都蒲江民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006854"},{"bank_alias":"耒阳融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006855"},{"bank_alias":"远安金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006857"},{"bank_alias":"临泉中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006858"},{"bank_alias":"浙江桐乡民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006859"},{"bank_alias":"弥勒沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006860"},{"bank_alias":"隆尧邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006861"},{"bank_alias":"罗田楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006862"},{"bank_alias":"突泉蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006863"},{"bank_alias":"北京怀柔融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006865"},{"bank_alias":"龙口中银富登南山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006866"},{"bank_alias":"卢龙家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006867"},{"bank_alias":"莱州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006868"},{"bank_alias":"确山郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006869"},{"bank_alias":"东源泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006870"},{"bank_alias":"吉林昌邑榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006871"},{"bank_alias":"北京延庆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006872"},{"bank_alias":"北京大兴华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006873"},{"bank_alias":"安徽利辛湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006874"},{"bank_alias":"榆树融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006875"},{"bank_alias":"太仓民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006876"},{"bank_alias":"大名恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006877"},{"bank_alias":"石首楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006878"},{"bank_alias":"浙江遂昌富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006879"},{"bank_alias":"四川江油华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006880"},{"bank_alias":"玉溪红塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006881"},{"bank_alias":"西双版纳勐腊长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006882"},{"bank_alias":"扶风浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006883"},{"bank_alias":"抚顺望花抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006884"},{"bank_alias":"铁门关津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006885"},{"bank_alias":"湖南安化湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006886"},{"bank_alias":"昆山鹿城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006887"},{"bank_alias":"吉县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006888"},{"bank_alias":"关岭恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006889"},{"bank_alias":"衡南浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006891"},{"bank_alias":"绵竹浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006892"},{"bank_alias":"贞丰兴贞村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006893"},{"bank_alias":"昆明石林中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006894"},{"bank_alias":"栖霞中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006895"},{"bank_alias":"云南新平北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006896"},{"bank_alias":"安福中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006897"},{"bank_alias":"珠海横琴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006898"},{"bank_alias":"泰安沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006899"},{"bank_alias":"范县德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006901"},{"bank_alias":"陕西富平汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006902"},{"bank_alias":"达州达川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006903"},{"bank_alias":"鄂尔多斯市塔拉壕金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006904"},{"bank_alias":"浙江庆元泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006905"},{"bank_alias":"山东博兴新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006906"},{"bank_alias":"湖南湘阴星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006907"},{"bank_alias":"扬中恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006908"},{"bank_alias":"深圳坪山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006909"},{"bank_alias":"安徽固镇新淮河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006910"},{"bank_alias":"保山施甸长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006911"},{"bank_alias":"安徽祁门铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006912"},{"bank_alias":"浙江缙云联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006913"},{"bank_alias":"上蔡惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006914"},{"bank_alias":"浙江台州路桥富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006915"},{"bank_alias":"昌黎家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006916"},{"bank_alias":"安徽太湖江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006917"},{"bank_alias":"丽江玉龙长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006918"},{"bank_alias":"通榆农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006919"},{"bank_alias":"山东文登中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006920"},{"bank_alias":"安徽宿松民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006922"},{"bank_alias":"兴化苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006923"},{"bank_alias":"湖南隆回湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006924"},{"bank_alias":"康保银丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006925"},{"bank_alias":"宁夏惠农贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006926"},{"bank_alias":"陕西安塞中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006927"},{"bank_alias":"五大连池惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006928"},{"bank_alias":"文山民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006930"},{"bank_alias":"重庆江北恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006931"},{"bank_alias":"万安洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006932"},{"bank_alias":"大理洱源长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006935"},{"bank_alias":"浙江龙泉民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006936"},{"bank_alias":"广州番禺新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006937"},{"bank_alias":"湖北赤壁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006938"},{"bank_alias":"湛江廉江长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006939"},{"bank_alias":"沧州海兴新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006940"},{"bank_alias":"漳浦民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006941"},{"bank_alias":"湖南安仁新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006942"},{"bank_alias":"邢台县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006943"},{"bank_alias":"敦化江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006944"},{"bank_alias":"辽宁凌海锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006945"},{"bank_alias":"东明中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006946"},{"bank_alias":"惠东惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006947"},{"bank_alias":"邯郸肥乡恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006948"},{"bank_alias":"清河金农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006949"},{"bank_alias":"营口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006950"},{"bank_alias":"广东海丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006953"},{"bank_alias":"湖南嘉禾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006957"},{"bank_alias":"湖南新宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006958"},{"bank_alias":"四川三台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006960"},{"bank_alias":"湖南耒阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006964"},{"bank_alias":"河北张北农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006966"},{"bank_alias":"四川绵竹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006968"},{"bank_alias":"白山江源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006970"},{"bank_alias":"四川岳池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006971"},{"bank_alias":"四川富顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006973"},{"bank_alias":"湖南会同农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006974"},{"bank_alias":"河北安平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006975"},{"bank_alias":"湖南临澧农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006977"},{"bank_alias":"河北怀来农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006978"},{"bank_alias":"吉林春城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006979"},{"bank_alias":"营口融生农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006980"},{"bank_alias":"湖南新田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006982"},{"bank_alias":"湖南沅江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006984"},{"bank_alias":"张家界农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006985"},{"bank_alias":"河北万全农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006986"},{"bank_alias":"江苏常熟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006987"},{"bank_alias":"宜宾翠屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006988"},{"bank_alias":"吉林舒兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006989"},{"bank_alias":"贵州息烽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006990"},{"bank_alias":"常德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006992"},{"bank_alias":"眉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006993"},{"bank_alias":"四川大竹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006995"},{"bank_alias":"辽宁大石桥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006996"},{"bank_alias":"长白山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006997"},{"bank_alias":"潮州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006998"},{"bank_alias":"延边农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007000"},{"bank_alias":"永州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007001"},{"bank_alias":"四川仁寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007002"},{"bank_alias":"四川青川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007003"},{"bank_alias":"长沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007004"},{"bank_alias":"吉林德惠农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007007"},{"bank_alias":"江苏昆山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007008"},{"bank_alias":"湖南湘阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007010"},{"bank_alias":"贵州从江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007011"},{"bank_alias":"吉林安图农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007013"},{"bank_alias":"河北蠡州北银农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007017"},{"bank_alias":"贵州紫云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007018"},{"bank_alias":"湖南靖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007019"},{"bank_alias":"四川剑阁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007020"},{"bank_alias":"沈阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007021"},{"bank_alias":"河北任县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007022"},{"bank_alias":"辽宁大洼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007023"},{"bank_alias":"辽宁建平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007026"},{"bank_alias":"四川兴文石海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007027"},{"bank_alias":"吉林东丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007028"},{"bank_alias":"湖南溆浦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007029"},{"bank_alias":"贵州毕节农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007031"},{"bank_alias":"湖南宁远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007034"},{"bank_alias":"石家庄鹿泉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007036"},{"bank_alias":"湖南通道农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007037"},{"bank_alias":"吉林临江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007038"},{"bank_alias":"河北南和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007042"},{"bank_alias":"河北香河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007043"},{"bank_alias":"辽宁灯塔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007044"},{"bank_alias":"吉林和龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007045"},{"bank_alias":"河北景州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007046"},{"bank_alias":"河北唐山曹妃甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007047"},{"bank_alias":"贵州兴义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007049"},{"bank_alias":"四川安州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007050"},{"bank_alias":"河北邯郸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007051"},{"bank_alias":"丹东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007052"},{"bank_alias":"湖南湘乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007055"},{"bank_alias":"湖南安乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007056"},{"bank_alias":"吉林龙井农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007057"},{"bank_alias":"湖南桂东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007060"},{"bank_alias":"河北涞水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007061"},{"bank_alias":"吉林珲春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007062"},{"bank_alias":"湖南衡山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007063"},{"bank_alias":"四川西充农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007065"},{"bank_alias":"吉林通化海科农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007066"},{"bank_alias":"张家口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007067"},{"bank_alias":"河北定州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007070"},{"bank_alias":"贵州独山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007071"},{"bank_alias":"湖南冷水江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007073"},{"bank_alias":"四川古蔺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007076"},{"bank_alias":"四川南部农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007077"},{"bank_alias":"吉林浑江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007078"},{"bank_alias":"河北滦州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007080"},{"bank_alias":"辽宁新民农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007081"},{"bank_alias":"贵州平塘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007084"},{"bank_alias":"太仓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007085"},{"bank_alias":"吉林汪清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007086"},{"bank_alias":"贵州花溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007087"},{"bank_alias":"贵州丹寨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007089"},{"bank_alias":"云南瑞丽南屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007091"},{"bank_alias":"湖南临武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007092"},{"bank_alias":"苏州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007093"},{"bank_alias":"河北晋州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007094"},{"bank_alias":"辽宁沈本农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007095"},{"bank_alias":"江苏江南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007096"},{"bank_alias":"四川蓬溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007097"},{"bank_alias":"河北柏乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007098"},{"bank_alias":"四川仪陇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007099"},{"bank_alias":"河北永清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007100"},{"bank_alias":"葫芦岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007101"},{"bank_alias":"贵州黔西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007102"},{"bank_alias":"湖南炎陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007103"},{"bank_alias":"河北邢台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007104"},{"bank_alias":"四川梓潼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007105"},{"bank_alias":"贵州湄潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007107"},{"bank_alias":"河北衡水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007108"},{"bank_alias":"湖南凤凰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007110"},{"bank_alias":"四川合江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007112"},{"bank_alias":"四川长宁竹海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007117"},{"bank_alias":"湖南花垣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007118"},{"bank_alias":"贵州余庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007119"},{"bank_alias":"湖南中方农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007120"},{"bank_alias":"四川筠连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007121"},{"bank_alias":"辽阳辽东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007122"},{"bank_alias":"吉林九台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007123"},{"bank_alias":"贵州兴仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007124"},{"bank_alias":"湖南祁东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007125"},{"bank_alias":"河北承德热河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007127"},{"bank_alias":"湖南常宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007128"},{"bank_alias":"宜宾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007129"},{"bank_alias":"铜仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007130"},{"bank_alias":"辽宁沈抚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007133"},{"bank_alias":"河北临城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007134"},{"bank_alias":"河北高碑店农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007137"},{"bank_alias":"贵州镇远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007138"},{"bank_alias":"成都农商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007140"},{"bank_alias":"河北三河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007141"},{"bank_alias":"衡阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007142"},{"bank_alias":"辽宁本溪南芬农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007143"},{"bank_alias":"辽宁盖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007144"},{"bank_alias":"河北井陉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007145"},{"bank_alias":"湖南麻阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007146"},{"bank_alias":"贵州黎平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007147"},{"bank_alias":"张家港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007148"},{"bank_alias":"贵州晴隆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007150"},{"bank_alias":"湘潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007151"},{"bank_alias":"湖南双峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007152"},{"bank_alias":"株洲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007153"},{"bank_alias":"湖南新邵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007154"},{"bank_alias":"湖南韶山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007155"},{"bank_alias":"贵州天柱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007156"},{"bank_alias":"河北玉田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007157"},{"bank_alias":"辽宁清原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007160"},{"bank_alias":"湖南古丈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007161"},{"bank_alias":"河北巨鹿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007163"},{"bank_alias":"江苏太仓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007164"},{"bank_alias":"四川叙永农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007167"},{"bank_alias":"广安思源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007168"},{"bank_alias":"贵州黄平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007169"},{"bank_alias":"河北南和农商行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007170"},{"bank_alias":"四川犍为农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007171"},{"bank_alias":"河北邢州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007172"},{"bank_alias":"湖南华容农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007173"},{"bank_alias":"湖南株洲珠江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007175"},{"bank_alias":"湖南衡东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007176"},{"bank_alias":"四川泸县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007177"},{"bank_alias":"湖南绥宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007179"},{"bank_alias":"湖南洪江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007180"},{"bank_alias":"河北卢龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007181"},{"bank_alias":"四川罗江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007182"},{"bank_alias":"河北唐山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007184"},{"bank_alias":"贵州惠水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007189"},{"bank_alias":"四川隆昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007191"},{"bank_alias":"河北保定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007193"},{"bank_alias":"四川屏山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007194"},{"bank_alias":"湖南汉寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007196"},{"bank_alias":"河北阳原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007197"},{"bank_alias":"宜宾南溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007198"},{"bank_alias":"贵州玉屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007200"},{"bank_alias":"四川武胜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007203"},{"bank_alias":"河北滦平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007205"},{"bank_alias":"湖南城步农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007206"},{"bank_alias":"六盘水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007207"},{"bank_alias":"攀枝花农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007209"},{"bank_alias":"南充农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007210"},{"bank_alias":"湖南澧县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007211"},{"bank_alias":"湖南娄底农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007212"},{"bank_alias":"贵州三都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007213"},{"bank_alias":"贵州思南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007214"},{"bank_alias":"常熟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007216"},{"bank_alias":"河北宁晋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007218"},{"bank_alias":"湖南泸溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007219"},{"bank_alias":"河北大名农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007220"},{"bank_alias":"四川威远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007221"},{"bank_alias":"四川丹棱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007222"},{"bank_alias":"益阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007223"},{"bank_alias":"湖南永兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007224"},{"bank_alias":"吉林靖宇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007225"},{"bank_alias":"四川渠县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007226"},{"bank_alias":"遂宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007227"},{"bank_alias":"湖南永顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007228"},{"bank_alias":"四川广汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007230"},{"bank_alias":"雅安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007231"},{"bank_alias":"阳江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007232"},{"bank_alias":"吉林通榆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007235"},{"bank_alias":"湖南桂阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007236"},{"bank_alias":"湖南南岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007237"},{"bank_alias":"四川万源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007238"},{"bank_alias":"四川平武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007239"},{"bank_alias":"吉林辉南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007241"},{"bank_alias":"湖南道县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007242"},{"bank_alias":"湖南临湘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007243"},{"bank_alias":"湖南芷江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007244"},{"bank_alias":"自贡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007245"},{"bank_alias":"湖南东安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007246"},{"bank_alias":"贵州道真农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007247"},{"bank_alias":"河北献县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007248"},{"bank_alias":"贵州遵义汇川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007249"},{"bank_alias":"湖南湘潭天易农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007250"},{"bank_alias":"湖南祁阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007251"},{"bank_alias":"吉林环城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007252"},{"bank_alias":"吉林双阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007253"},{"bank_alias":"四川青神农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007254"},{"bank_alias":"河北涿鹿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007256"},{"bank_alias":"湖南安化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007259"},{"bank_alias":"凉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007262"},{"bank_alias":"吉林永吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007264"},{"bank_alias":"湖南桃江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007266"},{"bank_alias":"湖南辰溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007267"},{"bank_alias":"通化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007268"},{"bank_alias":"湖南岳阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007269"},{"bank_alias":"河北正定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007270"},{"bank_alias":"河北宽城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007271"},{"bank_alias":"吉林大安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007272"},{"bank_alias":"湖南星沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007273"},{"bank_alias":"鞍山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007274"},{"bank_alias":"湖南江华农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007275"},{"bank_alias":"湖南龙山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007276"},{"bank_alias":"贵州三穗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007279"},{"bank_alias":"吉林柳河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007281"},{"bank_alias":"河北沽源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007282"},{"bank_alias":"辽宁岫岩农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007283"},{"bank_alias":"内江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007284"},{"bank_alias":"湖南汨罗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007285"},{"bank_alias":"成都农商行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007287"},{"bank_alias":"四川阆中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007288"},{"bank_alias":"贵州桐梓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007290"},{"bank_alias":"湖南汝城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007291"},{"bank_alias":"辽阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007292"},{"bank_alias":"四川简阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007298"},{"bank_alias":"贵州遵义红花岗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007300"},{"bank_alias":"吉林公主岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007303"},{"bank_alias":"泸州江阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007305"},{"bank_alias":"长春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007306"},{"bank_alias":"湖南江永农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007307"},{"bank_alias":"河北深州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007308"},{"bank_alias":"四川苍溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007309"},{"bank_alias":"河北霸州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007310"},{"bank_alias":"吉林农安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007311"},{"bank_alias":"泸州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007313"},{"bank_alias":"贵州凤冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007315"},{"bank_alias":"湖南醴陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007316"},{"bank_alias":"怀化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007317"},{"bank_alias":"河北灵寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007318"},{"bank_alias":"湖南平江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007319"},{"bank_alias":"贵州赫章农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007324"},{"bank_alias":"长春发展农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007325"},{"bank_alias":"贵州安龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007327"},{"bank_alias":"吉林桦甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007328"},{"bank_alias":"广州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007329"},{"bank_alias":"河北涿州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007330"},{"bank_alias":"吉林镇赉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007333"},{"bank_alias":"贵州麻江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007334"},{"bank_alias":"贵州福泉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007335"},{"bank_alias":"湖南浏阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007336"},{"bank_alias":"河北黄骅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007338"},{"bank_alias":"贵州仁怀茅台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007339"},{"bank_alias":"湖南慈利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007341"},{"bank_alias":"重庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007343"},{"bank_alias":"四川射洪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007344"},{"bank_alias":"湖南衡南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007346"},{"bank_alias":"江苏张家港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007347"},{"bank_alias":"河北迁安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007351"},{"bank_alias":"郴州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007352"},{"bank_alias":"泸州龙马潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007353"},{"bank_alias":"湖南安仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007355"},{"bank_alias":"湖南蓝山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007356"},{"bank_alias":"辽宁新宾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007357"},{"bank_alias":"河北沙河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007359"},{"bank_alias":"吉林榆树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007361"},{"bank_alias":"湖南双牌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007362"},{"bank_alias":"湖南资兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007364"},{"bank_alias":"贵州都匀农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007365"},{"bank_alias":"贵州大方农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007366"},{"bank_alias":"吉林集安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007369"},{"bank_alias":"贵州普定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007370"},{"bank_alias":"吉林蛟河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007371"},{"bank_alias":"湖南津市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007372"},{"bank_alias":"河北滦南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007373"},{"bank_alias":"湖南桑植农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007374"},{"bank_alias":"河北固安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007375"},{"bank_alias":"河北元氏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007377"},{"bank_alias":"四川什邡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007378"},{"bank_alias":"贵州织金农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007379"},{"bank_alias":"湖南洞口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007380"},{"bank_alias":"辽宁宽甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007383"},{"bank_alias":"贵州乌当农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007385"},{"bank_alias":"贵州清镇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007387"},{"bank_alias":"锦州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007388"},{"bank_alias":"河北清河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007389"},{"bank_alias":"辽源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007393"},{"bank_alias":"河北文安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007395"},{"bank_alias":"广元农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007397"},{"bank_alias":"湖南南县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007399"},{"bank_alias":"河北辛集农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007401"},{"bank_alias":"四川峨眉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007402"},{"bank_alias":"贵州贵定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007406"},{"bank_alias":"吉林磐石农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007407"},{"bank_alias":"湖南吉首农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007409"},{"bank_alias":"贵州普安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007410"},{"bank_alias":"河北涉县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007412"},{"bank_alias":"河北广宗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007413"},{"bank_alias":"四川华蓥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007414"},{"bank_alias":"湖南隆回农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007415"},{"bank_alias":"湖南攸县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007416"},{"bank_alias":"湖南桃源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007418"},{"bank_alias":"达州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007419"},{"bank_alias":"四川营山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007420"},{"bank_alias":"河北丰宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007421"},{"bank_alias":"巴中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007422"},{"bank_alias":"河北冀州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007423"},{"bank_alias":"河北阜城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007425"},{"bank_alias":"河北安国农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007427"},{"bank_alias":"四川高县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007428"},{"bank_alias":"湖南保靖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007430"},{"bank_alias":"昆山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007431"},{"bank_alias":"吉林郭尔罗斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007433"},{"bank_alias":"辽宁桓仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007434"},{"bank_alias":"辽宁海城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007435"},{"bank_alias":"河北临西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007436"},{"bank_alias":"辽宁兴城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007437"},{"bank_alias":"贵州遵义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007438"},{"bank_alias":"湖南省湘乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007439"},{"bank_alias":"湖南湘江新区农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007440"},{"bank_alias":"四川宣汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007441"},{"bank_alias":"辽宁凤城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007442"},{"bank_alias":"四川珙县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007445"},{"bank_alias":"四川邻水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007446"},{"bank_alias":"四川宜宾金江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007447"},{"bank_alias":"辽宁东港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007448"},{"bank_alias":"河北围场农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007450"},{"bank_alias":"江苏苏州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007452"},{"bank_alias":"贵州瓮安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007453"},{"bank_alias":"河北枣强农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007454"},{"bank_alias":"湖南宁乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007455"},{"bank_alias":"贵州龙里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007456"},{"bank_alias":"吉林敦化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007457"},{"bank_alias":"四川江安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007458"},{"bank_alias":"四川安岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007459"},{"bank_alias":"大连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007462"},{"bank_alias":"湖南石门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007467"},{"bank_alias":"湖南武冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007469"},{"bank_alias":"贵州贞丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007470"},{"bank_alias":"湖南沅陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007472"},{"bank_alias":"河北大厂农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007474"},{"bank_alias":"湖南邵阳昭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007477"},{"bank_alias":"江苏江阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007478"},{"bank_alias":"湖南茶陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007483"},{"bank_alias":"成都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007484"},{"bank_alias":"河北南皮农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007485"},{"bank_alias":"贵州荔波农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007487"},{"bank_alias":"资阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007488"},{"bank_alias":"安顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007489"},{"bank_alias":"河北平山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007491"},{"bank_alias":"邵阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007492"},{"bank_alias":"湖南宜章农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007494"},{"bank_alias":"河北武强农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007496"},{"bank_alias":"德阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007497"},{"bank_alias":"河北鸡泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007498"},{"bank_alias":"四川乐至农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007500"},{"bank_alias":"湖南新晃农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007503"},{"bank_alias":"湖南涟源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007504"},{"bank_alias":"河北张家口宣泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007505"},{"bank_alias":"四川大英农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007507"},{"bank_alias":"广安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007508"},{"bank_alias":"贵州关岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007509"},{"bank_alias":"河北沧州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007511"},{"bank_alias":"湖南新化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007512"},{"bank_alias":"湖南岳阳巴陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007515"},{"bank_alias":"湖南邵东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007516"},{"bank_alias":"海口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007517"},{"bank_alias":"贵州凯里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007519"},{"bank_alias":"贵州修文农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007520"},{"bank_alias":"贵州务川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007521"},{"bank_alias":"白城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007522"},{"bank_alias":"阜新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007523"},{"bank_alias":"湖南衡阳衡州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007524"},{"bank_alias":"阿合奇县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007531"},{"bank_alias":"本溪市桥头农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007532"},{"bank_alias":"江城哈尼族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007533"},{"bank_alias":"泸西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007534"},{"bank_alias":"汶川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007537"},{"bank_alias":"湖北恩施农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007538"},{"bank_alias":"云南大姚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007539"},{"bank_alias":"曲靖市沾益区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007544"},{"bank_alias":"江西广昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007545"},{"bank_alias":"康定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007546"},{"bank_alias":"湖北应城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007547"},{"bank_alias":"宜良县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007553"},{"bank_alias":"青海同仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007555"},{"bank_alias":"民丰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007558"},{"bank_alias":"资中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007559"},{"bank_alias":"宁夏青铜峡市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007561"},{"bank_alias":"江西赣县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007562"},{"bank_alias":"湖北鄂州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007563"},{"bank_alias":"江西樟树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007565"},{"bank_alias":"山东莱芜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007566"},{"bank_alias":"山东无棣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007568"},{"bank_alias":"于田县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007570"},{"bank_alias":"黑龙江抚远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007573"},{"bank_alias":"江西高安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007575"},{"bank_alias":"勐海县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007577"},{"bank_alias":"依兰县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007579"},{"bank_alias":"云南梁河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007581"},{"bank_alias":"得荣县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007586"},{"bank_alias":"抚顺县东四路农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007590"},{"bank_alias":"广平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007591"},{"bank_alias":"昆明市五华区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007593"},{"bank_alias":"新龙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007599"},{"bank_alias":"黑龙江省牡丹江市城郊农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007601"},{"bank_alias":"烟台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007604"},{"bank_alias":"察布查尔县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007607"},{"bank_alias":"本溪市市区兴达农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007611"},{"bank_alias":"云南昭通昭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007612"},{"bank_alias":"皮山县桑株乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007613"},{"bank_alias":"抚松县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007617"},{"bank_alias":"海林市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007618"},{"bank_alias":"宁安市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007620"},{"bank_alias":"宣威市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007623"},{"bank_alias":"江西芦溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007624"},{"bank_alias":"江西井冈山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007630"},{"bank_alias":"朝阳县新华路农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007631"},{"bank_alias":"山东禹城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007633"},{"bank_alias":"德州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007634"},{"bank_alias":"曲靖市马龙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007635"},{"bank_alias":"榕江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007640"},{"bank_alias":"黑龙江泰来农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007641"},{"bank_alias":"尼勒克县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007642"},{"bank_alias":"云南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007643"},{"bank_alias":"双辽市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007646"},{"bank_alias":"宁夏中宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007648"},{"bank_alias":"馆陶县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007649"},{"bank_alias":"昌江黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007653"},{"bank_alias":"山东临清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007656"},{"bank_alias":"张家口市宣化农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007657"},{"bank_alias":"寿光农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007658"},{"bank_alias":"黑龙江省望奎县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007661"},{"bank_alias":"青海民和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007662"},{"bank_alias":"疏附县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007664"},{"bank_alias":"山东乐陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007665"},{"bank_alias":"盐山县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007670"},{"bank_alias":"江西万年农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007671"},{"bank_alias":"江西泰和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007672"},{"bank_alias":"峨山彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007673"},{"bank_alias":"湖北孝感农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007675"},{"bank_alias":"江西庐山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007676"},{"bank_alias":"迁安市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007684"},{"bank_alias":"内丘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007685"},{"bank_alias":"济南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007686"},{"bank_alias":"赵县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007690"},{"bank_alias":"抚顺县拉古农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007691"},{"bank_alias":"云南云龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007692"},{"bank_alias":"江西黎川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007694"},{"bank_alias":"云南玉溪红塔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007698"},{"bank_alias":"山东平原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007701"},{"bank_alias":"云南宾川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007703"},{"bank_alias":"哈尔滨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007705"},{"bank_alias":"山东宁阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007706"},{"bank_alias":"皮山县杜瓦镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007711"},{"bank_alias":"中江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007712"},{"bank_alias":"山东巨野农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007713"},{"bank_alias":"江西兴国农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007716"},{"bank_alias":"青海格尔木农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007717"},{"bank_alias":"赣州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007718"},{"bank_alias":"绿春县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007720"},{"bank_alias":"彰武县冯家农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007726"},{"bank_alias":"宁洱哈尼族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007728"},{"bank_alias":"昆明市东川区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007729"},{"bank_alias":"东营农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007731"},{"bank_alias":"永仁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007736"},{"bank_alias":"兴隆县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007739"},{"bank_alias":"湖北荆州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007740"},{"bank_alias":"青海海晏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007743"},{"bank_alias":"湖北三峡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007745"},{"bank_alias":"兰坪县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007747"},{"bank_alias":"泸水市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007749"},{"bank_alias":"黑龙江省肇东市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007753"},{"bank_alias":"江西宜黄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007755"},{"bank_alias":"菏泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007757"},{"bank_alias":"建昌县喇嘛洞农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007758"},{"bank_alias":"梨树县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007759"},{"bank_alias":"井研县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007760"},{"bank_alias":"云南嵩明农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007762"},{"bank_alias":"湖北崇阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007763"},{"bank_alias":"民丰县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007765"},{"bank_alias":"乡城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007766"},{"bank_alias":"福建省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007768"},{"bank_alias":"湖北仙桃农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007770"},{"bank_alias":"福海县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007774"},{"bank_alias":"湖北通山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007776"},{"bank_alias":"青海大通农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007780"},{"bank_alias":"新疆伊犁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007781"},{"bank_alias":"绥化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007783"},{"bank_alias":"湖北监利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007784"},{"bank_alias":"湖北南漳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007787"},{"bank_alias":"齐齐哈尔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007791"},{"bank_alias":"肇东市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007793"},{"bank_alias":"山东荣成农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007794"},{"bank_alias":"赞皇县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007795"},{"bank_alias":"长顺县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007797"},{"bank_alias":"湖北郧县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007798"},{"bank_alias":"红河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007800"},{"bank_alias":"哈尔滨市呼兰区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007802"},{"bank_alias":"扶余市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007804"},{"bank_alias":"云南马关农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007807"},{"bank_alias":"云南华宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007809"},{"bank_alias":"青海门源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007811"},{"bank_alias":"山东莒县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007812"},{"bank_alias":"山东莱州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007813"},{"bank_alias":"乐亭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007814"},{"bank_alias":"山东沂水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007815"},{"bank_alias":"宁夏石嘴山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007816"},{"bank_alias":"阜平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007818"},{"bank_alias":"山东省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007822"},{"bank_alias":"绥中县高岭农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007823"},{"bank_alias":"山东栖霞农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007825"},{"bank_alias":"金平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007830"},{"bank_alias":"宝兴县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007831"},{"bank_alias":"云南元谋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007832"},{"bank_alias":"白玉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007833"},{"bank_alias":"穆棱市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007835"},{"bank_alias":"黑龙江省鹤岗市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007836"},{"bank_alias":"易门县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007838"},{"bank_alias":"山东蓬莱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007839"},{"bank_alias":"北镇市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007840"},{"bank_alias":"澜沧拉祜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007841"},{"bank_alias":"江西弋阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007842"},{"bank_alias":"江西庐陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007845"},{"bank_alias":"宜春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007846"},{"bank_alias":"黑龙江克东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007847"},{"bank_alias":"涞源县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007850"},{"bank_alias":"桦川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007851"},{"bank_alias":"新疆库尔勒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007854"},{"bank_alias":"若羌县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007856"},{"bank_alias":"成安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007857"},{"bank_alias":"湖北大冶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007859"},{"bank_alias":"本溪市市区平山农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007860"},{"bank_alias":"云南洱源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007863"},{"bank_alias":"湖北松滋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007864"},{"bank_alias":"山东商河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007866"},{"bank_alias":"江西进贤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007868"},{"bank_alias":"黑龙江鸡西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007870"},{"bank_alias":"保亭黎族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007873"},{"bank_alias":"湖北武当山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007878"},{"bank_alias":"尚志市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007879"},{"bank_alias":"耿马傣族佤族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007880"},{"bank_alias":"黑龙江讷河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007883"},{"bank_alias":"陵水黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007887"},{"bank_alias":"华坪县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007891"},{"bank_alias":"湖北通城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007893"},{"bank_alias":"桦南县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007898"},{"bank_alias":"华宁县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007899"},{"bank_alias":"通山楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007900"},{"bank_alias":"山东单县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007905"},{"bank_alias":"昆明官渡农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007906"},{"bank_alias":"湖北咸丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007909"},{"bank_alias":"湖北省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007911"},{"bank_alias":"东莞农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007915"},{"bank_alias":"台安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007916"},{"bank_alias":"壤塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007918"},{"bank_alias":"南宫市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007919"},{"bank_alias":"日照东港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007920"},{"bank_alias":"山东青州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007923"},{"bank_alias":"定兴县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007926"},{"bank_alias":"青海共和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007927"},{"bank_alias":"巩留县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007928"},{"bank_alias":"雄县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007929"},{"bank_alias":"新疆阜康农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007930"},{"bank_alias":"新疆喀什农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007934"},{"bank_alias":"调兵山市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007936"},{"bank_alias":"抚顺县农村信用社合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007937"},{"bank_alias":"江西宜丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007939"},{"bank_alias":"金川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007940"},{"bank_alias":"湖北麻城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007942"},{"bank_alias":"山东茌平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007947"},{"bank_alias":"昌黎县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007949"},{"bank_alias":"湖北黄冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007953"},{"bank_alias":"青龙满族自治县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007955"},{"bank_alias":"青海省农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007956"},{"bank_alias":"江西东乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007958"},{"bank_alias":"松原市宁江区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007959"},{"bank_alias":"南昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007960"},{"bank_alias":"岳普湖县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007963"},{"bank_alias":"江西横峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007964"},{"bank_alias":"湖北利川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007965"},{"bank_alias":"青海刚察农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007969"},{"bank_alias":"朝阳县柳城农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007970"},{"bank_alias":"哈巴河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007973"},{"bank_alias":"茂县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007977"},{"bank_alias":"山西省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007978"},{"bank_alias":"湖北阳新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007982"},{"bank_alias":"山东文登农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007983"},{"bank_alias":"潍坊市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007985"},{"bank_alias":"托克逊县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007988"},{"bank_alias":"皮山县科克铁热克乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007990"},{"bank_alias":"嘉荫县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007991"},{"bank_alias":"双鸭山市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007992"},{"bank_alias":"江西上犹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007995"},{"bank_alias":"大关县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007997"},{"bank_alias":"三亚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007998"},{"bank_alias":"建昌县八家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007999"},{"bank_alias":"南江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008000"},{"bank_alias":"宁夏吴忠农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008001"},{"bank_alias":"江西赣昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008003"},{"bank_alias":"荥经县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008004"},{"bank_alias":"沿河土家族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008005"},{"bank_alias":"黑龙江省桦川县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008006"},{"bank_alias":"皮山县藏桂乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008008"},{"bank_alias":"铁力市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008013"},{"bank_alias":"山东高密农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008014"},{"bank_alias":"额敏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008015"},{"bank_alias":"张家口市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008016"},{"bank_alias":"勃利县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008017"},{"bank_alias":"麦盖提县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008019"},{"bank_alias":"马尔康县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008022"},{"bank_alias":"海南万宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008023"},{"bank_alias":"山东广饶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008024"},{"bank_alias":"望奎县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008025"},{"bank_alias":"青海贵德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008027"},{"bank_alias":"德江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008030"},{"bank_alias":"平泉市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008031"},{"bank_alias":"朝阳市双塔区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008032"},{"bank_alias":"佳木斯市郊区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008034"},{"bank_alias":"宁夏石嘴山市惠农区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008036"},{"bank_alias":"无极县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008039"},{"bank_alias":"法库县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008040"},{"bank_alias":"旺苍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008041"},{"bank_alias":"石阡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008042"},{"bank_alias":"青海湟中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008044"},{"bank_alias":"景谷傣族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008045"},{"bank_alias":"盘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008046"},{"bank_alias":"汉源县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008049"},{"bank_alias":"云南云县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008050"},{"bank_alias":"阜新县十家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008051"},{"bank_alias":"西宁农商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008052"},{"bank_alias":"铁岭县新台子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008055"},{"bank_alias":"水城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008058"},{"bank_alias":"云南凤庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008059"},{"bank_alias":"黑龙江庆安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008061"},{"bank_alias":"蔚县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008062"},{"bank_alias":"黑龙江省铁力市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008063"},{"bank_alias":"定安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008064"},{"bank_alias":"朝阳市龙城区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008065"},{"bank_alias":"山东梁山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008067"},{"bank_alias":"河北省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008072"},{"bank_alias":"叶城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008074"},{"bank_alias":"海南屯昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008077"},{"bank_alias":"江西鄱阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008079"},{"bank_alias":"个旧市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008080"},{"bank_alias":"皮山县克里阳乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008081"},{"bank_alias":"江西省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008082"},{"bank_alias":"夹江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008083"},{"bank_alias":"本溪市市区农村信用合作社联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008084"},{"bank_alias":"富宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008086"},{"bank_alias":"黑龙江省依安县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008089"},{"bank_alias":"山东东平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008091"},{"bank_alias":"青海乌兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008093"},{"bank_alias":"稻城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008095"},{"bank_alias":"黑龙江逊克农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008096"},{"bank_alias":"湖北远安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008097"},{"bank_alias":"岑巩县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008098"},{"bank_alias":"保定市满城区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008099"},{"bank_alias":"石渠县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008100"},{"bank_alias":"黑龙江孙吴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008101"},{"bank_alias":"山东临邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008102"},{"bank_alias":"青海湟源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008106"},{"bank_alias":"湖北团风农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008107"},{"bank_alias":"依兰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008108"},{"bank_alias":"云南陇川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008109"},{"bank_alias":"日照岚山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008111"},{"bank_alias":"湖北咸宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008113"},{"bank_alias":"泊头市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008114"},{"bank_alias":"墨玉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008118"},{"bank_alias":"巧家县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008120"},{"bank_alias":"和静县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008121"},{"bank_alias":"双辽市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008125"},{"bank_alias":"山东济阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008126"},{"bank_alias":"湖北宣恩农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008128"},{"bank_alias":"吉安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008133"},{"bank_alias":"鹰潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008136"},{"bank_alias":"皮山县木奎拉乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008141"},{"bank_alias":"抚顺县上马农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008142"},{"bank_alias":"湖北嘉鱼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008143"},{"bank_alias":"昆明晋宁区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008144"},{"bank_alias":"隆化县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008150"},{"bank_alias":"青海泽库农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008151"},{"bank_alias":"康平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008152"},{"bank_alias":"伽师县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008153"},{"bank_alias":"本溪市市区通达农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008155"},{"bank_alias":"朝阳县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008156"},{"bank_alias":"富民县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008160"},{"bank_alias":"沈阳市苏家屯区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008161"},{"bank_alias":"黑龙江嫩江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008162"},{"bank_alias":"湖北鹤峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008165"},{"bank_alias":"宁夏平罗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008166"},{"bank_alias":"湖北枣阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008167"},{"bank_alias":"山东临沭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008168"},{"bank_alias":"山东鱼台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008169"},{"bank_alias":"新疆乌什农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008170"},{"bank_alias":"宁夏彭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008174"},{"bank_alias":"天全县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008178"},{"bank_alias":"青海化隆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008181"},{"bank_alias":"尚义县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008183"},{"bank_alias":"山东曲阜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008185"},{"bank_alias":"吐鲁番市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008186"},{"bank_alias":"湖北郧西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008187"},{"bank_alias":"江西瑞昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008188"},{"bank_alias":"台安县高力房农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008191"},{"bank_alias":"开江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008195"},{"bank_alias":"大城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008199"},{"bank_alias":"锦屏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008200"},{"bank_alias":"贡山独龙族怒族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008205"},{"bank_alias":"理县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008206"},{"bank_alias":"湖北大悟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008208"},{"bank_alias":"喀左县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008209"},{"bank_alias":"盘山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008210"},{"bank_alias":"墨江哈尼族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008212"},{"bank_alias":"曲阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008213"},{"bank_alias":"泽普县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008214"},{"bank_alias":"西丰县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008216"},{"bank_alias":"依安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008217"},{"bank_alias":"皮山县阔什塔格乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008218"},{"bank_alias":"淄博淄川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008219"},{"bank_alias":"永年县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008222"},{"bank_alias":"黑龙江建三江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008224"},{"bank_alias":"抚顺县石文农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008228"},{"bank_alias":"青冈县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008229"},{"bank_alias":"山东张店农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008230"},{"bank_alias":"德州陵城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008231"},{"bank_alias":"滨州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008233"},{"bank_alias":"新疆沙雅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008234"},{"bank_alias":"云南勐腊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008235"},{"bank_alias":"东方市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008239"},{"bank_alias":"泸定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008241"},{"bank_alias":"黑龙江同江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008242"},{"bank_alias":"黑龙江饶河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008244"},{"bank_alias":"新疆富蕴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008245"},{"bank_alias":"深泽县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008249"},{"bank_alias":"江西新建农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008250"},{"bank_alias":"黑龙江省佳木斯市郊区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008251"},{"bank_alias":"新疆木垒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008252"},{"bank_alias":"海伦市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008254"},{"bank_alias":"江西德兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008257"},{"bank_alias":"山东昌邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008259"},{"bank_alias":"云南龙陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008260"},{"bank_alias":"黑龙江省海林市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008262"},{"bank_alias":"江西上栗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008264"},{"bank_alias":"六枝特区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008265"},{"bank_alias":"山东乳山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008266"},{"bank_alias":"青海尖扎农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008267"},{"bank_alias":"云南陆良农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008270"},{"bank_alias":"黑龙江汤原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008272"},{"bank_alias":"大兴安岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008273"},{"bank_alias":"台安县城郊农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008275"},{"bank_alias":"福贡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008277"},{"bank_alias":"本溪市卧龙农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008278"},{"bank_alias":"黑龙江密山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008281"},{"bank_alias":"江西吉水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008282"},{"bank_alias":"湖北当阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008283"},{"bank_alias":"抚州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008286"},{"bank_alias":"磁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008289"},{"bank_alias":"湖北沙洋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008290"},{"bank_alias":"西盟县农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008292"},{"bank_alias":"青海循化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008293"},{"bank_alias":"和田市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008294"},{"bank_alias":"山东鄄城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008295"},{"bank_alias":"镇沅彝族哈尼族拉祜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008297"},{"bank_alias":"绵阳市涪城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008298"},{"bank_alias":"云南新平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008301"},{"bank_alias":"琼中黎族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008304"},{"bank_alias":"漾濞彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008305"},{"bank_alias":"山东阳谷农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008309"},{"bank_alias":"黑龙江北安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008310"},{"bank_alias":"山东招远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008311"},{"bank_alias":"吴桥县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008312"},{"bank_alias":"黑龙江省富锦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008318"},{"bank_alias":"北票市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008320"},{"bank_alias":"山东费县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008321"},{"bank_alias":"黑龙江塔河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008322"},{"bank_alias":"湖北广水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008323"},{"bank_alias":"昆明市盘龙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008324"},{"bank_alias":"新疆塔城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008325"},{"bank_alias":"江西彭泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008331"},{"bank_alias":"本溪市石桥子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008332"},{"bank_alias":"石家庄市藁城农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008334"},{"bank_alias":"峨边彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008335"},{"bank_alias":"松桃苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008336"},{"bank_alias":"湖北保康农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008338"},{"bank_alias":"朝阳市龙城区西大营子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008344"},{"bank_alias":"新疆伊宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008346"},{"bank_alias":"策勒县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008347"},{"bank_alias":"塔什库尔干县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008349"},{"bank_alias":"山东汶上农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008351"},{"bank_alias":"赤城县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008355"},{"bank_alias":"台安县台安镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008356"},{"bank_alias":"山东东阿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008357"},{"bank_alias":"芦山县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008358"},{"bank_alias":"云南永平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008360"},{"bank_alias":"西丰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008361"},{"bank_alias":"东辽县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008362"},{"bank_alias":"山东临沂罗庄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008367"},{"bank_alias":"海南临高农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008369"},{"bank_alias":"正安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008372"},{"bank_alias":"荣县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008373"},{"bank_alias":"山东金乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008374"},{"bank_alias":"石家庄市矿区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008376"},{"bank_alias":"黑龙江省青冈县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008378"},{"bank_alias":"泸州市纳溪区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008379"},{"bank_alias":"蓬溪县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008381"},{"bank_alias":"长岭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008383"},{"bank_alias":"绥江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008384"},{"bank_alias":"于田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008386"},{"bank_alias":"上饶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008390"},{"bank_alias":"本溪市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008391"},{"bank_alias":"枣庄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008393"},{"bank_alias":"建昌县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008396"},{"bank_alias":"施秉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008401"},{"bank_alias":"江西遂川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008402"},{"bank_alias":"湖北长阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008406"},{"bank_alias":"铁岭市清河区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008407"},{"bank_alias":"山东五莲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008408"},{"bank_alias":"洪雅县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008409"},{"bank_alias":"江西峡江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008410"},{"bank_alias":"湖北秭归农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008411"},{"bank_alias":"江西安义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008412"},{"bank_alias":"凌海市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008413"},{"bank_alias":"吉木乃县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008417"},{"bank_alias":"新疆昭苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008418"},{"bank_alias":"巴里坤哈萨克自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008419"},{"bank_alias":"淄博博山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008420"},{"bank_alias":"江西玉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008422"},{"bank_alias":"精河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008423"},{"bank_alias":"湖北宜都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008424"},{"bank_alias":"五指山市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008426"},{"bank_alias":"青铜峡市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008429"},{"bank_alias":"湖北罗田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008430"},{"bank_alias":"遵化市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008432"},{"bank_alias":"嘉荫县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008433"},{"bank_alias":"萍乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008435"},{"bank_alias":"江西万安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008442"},{"bank_alias":"山东新泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008444"},{"bank_alias":"云南大理市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008446"},{"bank_alias":"黑龙江集贤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008447"},{"bank_alias":"江西修水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008448"},{"bank_alias":"镇康县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008449"},{"bank_alias":"宁夏同心农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008450"},{"bank_alias":"山东武城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008451"},{"bank_alias":"黑龙江萝北农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008454"},{"bank_alias":"江西安远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008456"},{"bank_alias":"祥云县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008460"},{"bank_alias":"绥中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008462"},{"bank_alias":"永善县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008464"},{"bank_alias":"丽江古城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008467"},{"bank_alias":"黑龙江克山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008470"},{"bank_alias":"新疆呼图壁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008472"},{"bank_alias":"乐山三江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008476"},{"bank_alias":"云南南华农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008477"},{"bank_alias":"湖北老河口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008480"},{"bank_alias":"东光县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008481"},{"bank_alias":"黑龙江省穆棱市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008482"},{"bank_alias":"顺平县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008483"},{"bank_alias":"凌源市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008484"},{"bank_alias":"皮山县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008485"},{"bank_alias":"山东东明农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008486"},{"bank_alias":"皮山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008489"},{"bank_alias":"贵州省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008491"},{"bank_alias":"青海天峻农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008494"},{"bank_alias":"河间市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008496"},{"bank_alias":"江西南城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008497"},{"bank_alias":"山东平邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008498"},{"bank_alias":"北川羌族自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008501"},{"bank_alias":"山东诸城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008504"},{"bank_alias":"山东滕州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008506"},{"bank_alias":"赤水市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008508"},{"bank_alias":"台江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008511"},{"bank_alias":"辽宁省喀喇沁左翼蒙古族自治县公营子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008512"},{"bank_alias":"云南腾冲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008513"},{"bank_alias":"云南永胜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008516"},{"bank_alias":"永宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008517"},{"bank_alias":"新疆阿克苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008518"},{"bank_alias":"阿坝州农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008519"},{"bank_alias":"武汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008520"},{"bank_alias":"安新县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008521"},{"bank_alias":"铁岭县平顶堡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008523"},{"bank_alias":"鹤岗市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008525"},{"bank_alias":"江西崇仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008527"},{"bank_alias":"新河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008529"},{"bank_alias":"江西崇义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008530"},{"bank_alias":"新疆尉犁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008531"},{"bank_alias":"九龙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008533"},{"bank_alias":"皮山县皮亚勒玛乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008535"},{"bank_alias":"湖北随州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008538"},{"bank_alias":"山东定陶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008541"},{"bank_alias":"山东郯城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008542"},{"bank_alias":"伊通满族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008543"},{"bank_alias":"辽中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008544"},{"bank_alias":"容城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008547"},{"bank_alias":"山东龙口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008549"},{"bank_alias":"金沙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008551"},{"bank_alias":"抚顺县章党农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008552"},{"bank_alias":"山东安丘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008553"},{"bank_alias":"青海柴达木农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008554"},{"bank_alias":"曲靖市麒麟区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008560"},{"bank_alias":"黑龙江方正农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008561"},{"bank_alias":"特克斯县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008562"},{"bank_alias":"云南寻甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008564"},{"bank_alias":"泸县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008567"},{"bank_alias":"松潘县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008568"},{"bank_alias":"新疆石河子农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008570"},{"bank_alias":"黑龙江宾州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008571"},{"bank_alias":"云南普洱思茅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008573"},{"bank_alias":"石林彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008577"},{"bank_alias":"湖北竹溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008579"},{"bank_alias":"绥阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008580"},{"bank_alias":"山东成武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008584"},{"bank_alias":"武定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008588"},{"bank_alias":"鲁甸县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008591"},{"bank_alias":"黑龙江省兰西县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008593"},{"bank_alias":"石嘴山市惠农区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008596"},{"bank_alias":"无极县城关农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008597"},{"bank_alias":"黑龙江富裕农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008598"},{"bank_alias":"武邑县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008604"},{"bank_alias":"湖北黄梅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008606"},{"bank_alias":"本溪市市区东兴农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008608"},{"bank_alias":"黑龙江省海伦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008609"},{"bank_alias":"湖北丹江口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008613"},{"bank_alias":"岳池县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008616"},{"bank_alias":"四川省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008617"},{"bank_alias":"山东寿光农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008627"},{"bank_alias":"山东庆云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008629"},{"bank_alias":"阿图什市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008630"},{"bank_alias":"德钦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008631"},{"bank_alias":"青河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008632"},{"bank_alias":"黑龙江省林口县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008633"},{"bank_alias":"彰武县哈尔套农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008634"},{"bank_alias":"小金县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008636"},{"bank_alias":"大庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008637"},{"bank_alias":"义县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008638"},{"bank_alias":"巴楚县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008639"},{"bank_alias":"通江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008640"},{"bank_alias":"山东惠民农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008641"},{"bank_alias":"海南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008643"},{"bank_alias":"双江拉祜族佤族布朗族傣族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008645"},{"bank_alias":"湖北京山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008646"},{"bank_alias":"黑龙江漠河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008647"},{"bank_alias":"华安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008648"},{"bank_alias":"黑龙江省嘉荫县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008649"},{"bank_alias":"铁岭市银州区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008650"},{"bank_alias":"甘孜州农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008655"},{"bank_alias":"洛浦县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008657"},{"bank_alias":"昆明市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008658"},{"bank_alias":"且末县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008659"},{"bank_alias":"肥乡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008661"},{"bank_alias":"朝阳市龙城区七道泉子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008663"},{"bank_alias":"宁夏贺兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008664"},{"bank_alias":"江西会昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008669"},{"bank_alias":"云南巍山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008670"},{"bank_alias":"铁岭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008671"},{"bank_alias":"青海互助农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008673"},{"bank_alias":"云南鹤庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008677"},{"bank_alias":"策勒县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008678"},{"bank_alias":"魏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008682"},{"bank_alias":"宁夏西吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008685"},{"bank_alias":"昆明市西山区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008686"},{"bank_alias":"新乐市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008689"},{"bank_alias":"惠安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008690"},{"bank_alias":"新疆乌苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008693"},{"bank_alias":"沧源佤族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008698"},{"bank_alias":"富锦市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008699"},{"bank_alias":"云南隆阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008700"},{"bank_alias":"黑龙江鸡东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008701"},{"bank_alias":"云南临沧临翔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008706"},{"bank_alias":"七台河市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008707"},{"bank_alias":"凌源市城关镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008709"},{"bank_alias":"山东莒南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008710"},{"bank_alias":"新和县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008714"},{"bank_alias":"阿克陶县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008718"},{"bank_alias":"黄石农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008722"},{"bank_alias":"黑龙江绥棱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008724"},{"bank_alias":"黑龙江甘南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008726"},{"bank_alias":"新疆乌鲁木齐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008729"},{"bank_alias":"石屏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008733"},{"bank_alias":"山东临朐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008734"},{"bank_alias":"青县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008738"},{"bank_alias":"新疆博湖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008742"},{"bank_alias":"山东临沂河东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008743"},{"bank_alias":"湖北兴山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008745"},{"bank_alias":"湖北安陆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008747"},{"bank_alias":"江苏省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008748"},{"bank_alias":"山东博兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008749"},{"bank_alias":"蓬安县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008751"},{"bank_alias":"黑龙江东宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008752"},{"bank_alias":"青海都兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008754"},{"bank_alias":"绥中县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008755"},{"bank_alias":"兰西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008756"},{"bank_alias":"平乡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008757"},{"bank_alias":"山东垦利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008758"},{"bank_alias":"江西永修农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008759"},{"bank_alias":"唐县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008762"},{"bank_alias":"青海贵南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008764"},{"bank_alias":"隆尧县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008766"},{"bank_alias":"喀左县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008769"},{"bank_alias":"邯郸市峰峰矿区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008771"},{"bank_alias":"云南蒙自农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008773"},{"bank_alias":"长白朝鲜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008774"},{"bank_alias":"牡丹江市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008780"},{"bank_alias":"黑龙江省桦南县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008784"},{"bank_alias":"江西武宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008785"},{"bank_alias":"威县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008786"},{"bank_alias":"铁岭县凡河农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008788"},{"bank_alias":"江西都昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008789"},{"bank_alias":"黑龙江省牡丹江市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008792"},{"bank_alias":"聊城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008793"},{"bank_alias":"临漳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008794"},{"bank_alias":"湖北蕲春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008795"},{"bank_alias":"青海同德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008796"},{"bank_alias":"江油市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008797"},{"bank_alias":"台安县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008799"},{"bank_alias":"湖北赤壁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008806"},{"bank_alias":"罗甸县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008807"},{"bank_alias":"牟定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008808"},{"bank_alias":"黑山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008811"},{"bank_alias":"和布克赛尔县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008813"},{"bank_alias":"山东蒙阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008814"},{"bank_alias":"巴里坤哈萨克自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008815"},{"bank_alias":"勐腊县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008817"},{"bank_alias":"宁夏海原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008818"},{"bank_alias":"昆明市晋宁区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008820"},{"bank_alias":"故城县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008821"},{"bank_alias":"山东桓台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008822"},{"bank_alias":"镇雄县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008823"},{"bank_alias":"昌图县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008824"},{"bank_alias":"四平市城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008826"},{"bank_alias":"湖北孝昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008828"},{"bank_alias":"和田市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008830"},{"bank_alias":"江西广丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008831"},{"bank_alias":"湖北钟祥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008832"},{"bank_alias":"温泉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008833"},{"bank_alias":"阿图什市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008837"},{"bank_alias":"青岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008838"},{"bank_alias":"黑龙江省宁安市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008840"},{"bank_alias":"黑水县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008841"},{"bank_alias":"怀安县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008842"},{"bank_alias":"山东昌乐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008843"},{"bank_alias":"托里县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008844"},{"bank_alias":"木兰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008846"},{"bank_alias":"拜城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008847"},{"bank_alias":"吉林省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008849"},{"bank_alias":"龙江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008851"},{"bank_alias":"山东曹县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008852"},{"bank_alias":"开远市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008853"},{"bank_alias":"江川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008854"},{"bank_alias":"江西莲花农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008857"},{"bank_alias":"哈尔滨市依兰县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008858"},{"bank_alias":"江西石城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008860"},{"bank_alias":"平昌县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008862"},{"bank_alias":"山东郓城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008864"},{"bank_alias":"江西于都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008865"},{"bank_alias":"云南弥渡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008866"},{"bank_alias":"江西乐安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008867"},{"bank_alias":"湖北潜江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008870"},{"bank_alias":"印江土家族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008872"},{"bank_alias":"黑龙江虎林农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008874"},{"bank_alias":"山东肥城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008878"},{"bank_alias":"共青农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008881"},{"bank_alias":"孟村回族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008885"},{"bank_alias":"桦南县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008889"},{"bank_alias":"湖北天门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008890"},{"bank_alias":"彰武县后新秋农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008892"},{"bank_alias":"北票市五间房农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008895"},{"bank_alias":"剑川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008897"},{"bank_alias":"乐东黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008903"},{"bank_alias":"理塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008905"},{"bank_alias":"瑞丽市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008906"},{"bank_alias":"儋州市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008907"},{"bank_alias":"黑龙江省勃利县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008908"},{"bank_alias":"阜新蒙古族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008909"},{"bank_alias":"山东夏津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008910"},{"bank_alias":"江西上高农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008918"},{"bank_alias":"肃宁县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008919"},{"bank_alias":"伊春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008921"},{"bank_alias":"江西龙南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008925"},{"bank_alias":"本溪市市区富佳农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008929"},{"bank_alias":"江西靖安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008932"},{"bank_alias":"乐山市金口河区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008936"},{"bank_alias":"洮南市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008939"},{"bank_alias":"阜蒙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008940"},{"bank_alias":"色达县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008942"},{"bank_alias":"昆明市呈贡区农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008945"},{"bank_alias":"湖北竹山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008946"},{"bank_alias":"宁夏固原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008947"},{"bank_alias":"黑龙江肇州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008948"},{"bank_alias":"开原市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008952"},{"bank_alias":"雅江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008955"},{"bank_alias":"宁夏盐池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008956"},{"bank_alias":"江西瑞金农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008958"},{"bank_alias":"乐山市五通桥区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008962"},{"bank_alias":"元江哈尼族彝族傣族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008963"},{"bank_alias":"任丘市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008966"},{"bank_alias":"屏边县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008967"},{"bank_alias":"宁夏永宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008969"},{"bank_alias":"安宁市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008973"},{"bank_alias":"新疆温宿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008974"},{"bank_alias":"江西定南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008979"},{"bank_alias":"黑龙江肇源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008980"},{"bank_alias":"湖北谷城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008982"},{"bank_alias":"黑龙江五大连池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008985"},{"bank_alias":"哈尔滨市阿城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008986"},{"bank_alias":"炉霍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008989"},{"bank_alias":"永德县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008990"},{"bank_alias":"新疆奇台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008992"},{"bank_alias":"云南盈江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008994"},{"bank_alias":"黑龙江五常农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008995"},{"bank_alias":"云南水富农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008996"},{"bank_alias":"雷山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008997"},{"bank_alias":"黑龙江明水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008998"},{"bank_alias":"湖南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009000"},{"bank_alias":"潍坊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009006"},{"bank_alias":"宁夏中卫农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009008"},{"bank_alias":"行唐县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009009"},{"bank_alias":"辽宁省北票市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009010"},{"bank_alias":"望都县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009012"},{"bank_alias":"云南弥勒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009013"},{"bank_alias":"黑龙江林甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009015"},{"bank_alias":"云南禄丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009016"},{"bank_alias":"青冈县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009017"},{"bank_alias":"黑龙江宝清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009019"},{"bank_alias":"裕民县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009021"},{"bank_alias":"江西永丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009022"},{"bank_alias":"抚顺县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009023"},{"bank_alias":"和硕县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009024"},{"bank_alias":"德格县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009026"},{"bank_alias":"双鸭山市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009029"},{"bank_alias":"江西宁都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009030"},{"bank_alias":"疏勒县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009031"},{"bank_alias":"林口县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009032"},{"bank_alias":"九寨沟县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009033"},{"bank_alias":"青海果洛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009035"},{"bank_alias":"道孚县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009036"},{"bank_alias":"黑龙江安达农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009037"},{"bank_alias":"湖北来凤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009039"},{"bank_alias":"湖北十堰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009041"},{"bank_alias":"和布克赛尔蒙古自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009044"},{"bank_alias":"师宗县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009045"},{"bank_alias":"新疆霍城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009047"},{"bank_alias":"江西江州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009048"},{"bank_alias":"新疆沙湾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009050"},{"bank_alias":"本溪市市区东风农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009052"},{"bank_alias":"秦皇岛市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009053"},{"bank_alias":"朝阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009054"},{"bank_alias":"湖北浠水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009055"},{"bank_alias":"云南文山市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009059"},{"bank_alias":"青海玉树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009060"},{"bank_alias":"丹巴县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009063"},{"bank_alias":"湖北洪湖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009064"},{"bank_alias":"海南澄迈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009067"},{"bank_alias":"三河市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009068"},{"bank_alias":"拜泉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009069"},{"bank_alias":"云南施甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009071"},{"bank_alias":"山东周村农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009072"},{"bank_alias":"鹤岗市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009073"},{"bank_alias":"江西资溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009074"},{"bank_alias":"湖北宜城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009078"},{"bank_alias":"威宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009079"},{"bank_alias":"湖北襄阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009083"},{"bank_alias":"松桃苗族自治县信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009085"},{"bank_alias":"博野县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009086"},{"bank_alias":"新疆轮台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009088"},{"bank_alias":"云南建水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009090"},{"bank_alias":"望奎县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009091"},{"bank_alias":"盐亭县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009093"},{"bank_alias":"江西万载农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009094"},{"bank_alias":"湖北五峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009095"},{"bank_alias":"山东宁津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009099"},{"bank_alias":"将乐县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009101"},{"bank_alias":"山东高青农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009105"},{"bank_alias":"山东章丘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009106"},{"bank_alias":"佳木斯市郊区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009109"},{"bank_alias":"山东威海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009110"},{"bank_alias":"山东莘县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009111"},{"bank_alias":"邱北县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009114"},{"bank_alias":"景德镇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009116"},{"bank_alias":"云南玉龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009124"},{"bank_alias":"迁西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009129"},{"bank_alias":"云南威信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009130"},{"bank_alias":"梅河口市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009131"},{"bank_alias":"青海兴海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009134"},{"bank_alias":"禄劝彝族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009137"},{"bank_alias":"云南会泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009139"},{"bank_alias":"西畴县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009140"},{"bank_alias":"泰安泰山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009141"},{"bank_alias":"绵阳市游仙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009142"},{"bank_alias":"纳雍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009143"},{"bank_alias":"南涧彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009145"},{"bank_alias":"黑龙江友谊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009146"},{"bank_alias":"辽宁省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009148"},{"bank_alias":"江西湖口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009149"},{"bank_alias":"廊坊市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009150"},{"bank_alias":"铁力市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009152"},{"bank_alias":"哈尔滨市呼兰区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009154"},{"bank_alias":"台安县西佛农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009155"},{"bank_alias":"江西安福农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009156"},{"bank_alias":"江西大余农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009158"},{"bank_alias":"新疆博乐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009159"},{"bank_alias":"山东济宁兖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009164"},{"bank_alias":"朝阳市龙城区沈承农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009166"},{"bank_alias":"云南芒市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009168"},{"bank_alias":"和田县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009169"},{"bank_alias":"西丰县西丰镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009172"},{"bank_alias":"若尔盖县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009173"},{"bank_alias":"湖北石首农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009174"},{"bank_alias":"江西新干农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009176"},{"bank_alias":"曲周县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009177"},{"bank_alias":"双城市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009181"},{"bank_alias":"保定市徐水区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009185"},{"bank_alias":"山东聊城润昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009186"},{"bank_alias":"云南楚雄市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009188"},{"bank_alias":"彰武县东六家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009189"},{"bank_alias":"沧县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009190"},{"bank_alias":"海口市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009191"},{"bank_alias":"江西婺源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009192"},{"bank_alias":"山东沂源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009193"},{"bank_alias":"山东利津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009195"},{"bank_alias":"富源县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009196"},{"bank_alias":"湖北武穴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009198"},{"bank_alias":"黑河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009199"},{"bank_alias":"彰武县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009200"},{"bank_alias":"大田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009202"},{"bank_alias":"江西余干农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009203"},{"bank_alias":"山东莱阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009204"},{"bank_alias":"和田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009206"},{"bank_alias":"湖北红安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009211"},{"bank_alias":"沐川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009213"},{"bank_alias":"新疆昌吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009214"},{"bank_alias":"山东微山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009216"},{"bank_alias":"维西傈僳族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009224"},{"bank_alias":"山东临淄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009227"},{"bank_alias":"青海河南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009228"},{"bank_alias":"山东齐河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009229"},{"bank_alias":"新疆吉木萨尔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009235"},{"bank_alias":"山东莱州农村农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009236"},{"bank_alias":"云南景洪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009240"},{"bank_alias":"新疆天山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009242"},{"bank_alias":"海兴县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009243"},{"bank_alias":"黑龙江通河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009245"},{"bank_alias":"新疆维吾尔自治区农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009248"},{"bank_alias":"莎车县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009249"},{"bank_alias":"山东兰陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009250"},{"bank_alias":"乾安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009251"},{"bank_alias":"云南彝良农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009252"},{"bank_alias":"江西寻乌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009253"},{"bank_alias":"江西南丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009255"},{"bank_alias":"湖北房县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009256"},{"bank_alias":"巴彦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009257"},{"bank_alias":"抚顺县救兵农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009259"},{"bank_alias":"江西永新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009260"},{"bank_alias":"乐山市沙湾区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009262"},{"bank_alias":"巴塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009265"},{"bank_alias":"海伦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009266"},{"bank_alias":"江西湾里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009267"},{"bank_alias":"阿克陶县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009268"},{"bank_alias":"山东平阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009269"},{"bank_alias":"湖北枝江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009271"},{"bank_alias":"湖北云梦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009274"},{"bank_alias":"香格里拉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009275"},{"bank_alias":"江西铜鼓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009280"},{"bank_alias":"石棉县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009281"},{"bank_alias":"宁夏灵武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009282"},{"bank_alias":"湖北公安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009284"},{"bank_alias":"易县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009286"},{"bank_alias":"邯郸市城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009287"},{"bank_alias":"调兵山市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009289"},{"bank_alias":"肇东市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009291"},{"bank_alias":"山东嘉祥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009292"},{"bank_alias":"开阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009293"},{"bank_alias":"承德市郊区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009294"},{"bank_alias":"云南景东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009296"},{"bank_alias":"江西信丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009297"},{"bank_alias":"湖北建始农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009300"},{"bank_alias":"湖北荆门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009301"},{"bank_alias":"江口县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009302"},{"bank_alias":"凌源市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009303"},{"bank_alias":"云南祥云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009304"},{"bank_alias":"江西金溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009305"},{"bank_alias":"黑龙江绥滨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009307"},{"bank_alias":"平坝县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009309"},{"bank_alias":"山东阳信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009312"},{"bank_alias":"焉耆回族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009314"},{"bank_alias":"抚顺市顺城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009315"},{"bank_alias":"库车县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009323"},{"bank_alias":"云南通海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009324"},{"bank_alias":"山东海阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009325"},{"bank_alias":"江西全南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009326"},{"bank_alias":"本溪市北台农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009327"},{"bank_alias":"伊吾县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009328"},{"bank_alias":"山东长岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009329"},{"bank_alias":"新疆北屯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009332"},{"bank_alias":"甘孜县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009333"},{"bank_alias":"宁夏泾源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009336"},{"bank_alias":"姚安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009340"},{"bank_alias":"青海祁连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009342"},{"bank_alias":"皮山县农场农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009344"},{"bank_alias":"云南河口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009345"},{"bank_alias":"新余农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009351"},{"bank_alias":"朝阳市龙城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009352"},{"bank_alias":"江西丰城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009353"},{"bank_alias":"山东沂南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009355"},{"bank_alias":"玉溪市江川区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009356"},{"bank_alias":"湖北英山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009358"},{"bank_alias":"皮山县木吉乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009359"},{"bank_alias":"洛浦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009362"},{"bank_alias":"广东省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009366"},{"bank_alias":"黑龙江绥芬河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009367"},{"bank_alias":"马边彝族自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009370"},{"bank_alias":"山东邹城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009376"},{"bank_alias":"黑龙江杜尔伯特农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009378"},{"bank_alias":"湖北神农架农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009380"},{"bank_alias":"江西奉新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009381"},{"bank_alias":"邱县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009382"},{"bank_alias":"彰武县农村信用合作联四合城信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009383"},{"bank_alias":"云南易门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009386"},{"bank_alias":"江西广信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009388"},{"bank_alias":"北票市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009389"},{"bank_alias":"新疆阿勒泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009393"},{"bank_alias":"绥中县万家农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009394"},{"bank_alias":"英吉沙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009398"},{"bank_alias":"山东邹平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009404"},{"bank_alias":"泰安岱岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009407"},{"bank_alias":"康保县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009409"},{"bank_alias":"湖北江陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009412"},{"bank_alias":"青海西宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009414"},{"bank_alias":"本溪市高台子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009416"},{"bank_alias":"建昌县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009417"},{"bank_alias":"饶阳县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009418"},{"bank_alias":"红原县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009419"},{"bank_alias":"兰西县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009420"},{"bank_alias":"盐津县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009422"},{"bank_alias":"济宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009423"},{"bank_alias":"石家庄市矿区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009427"},{"bank_alias":"武安市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009430"},{"bank_alias":"云南广南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009431"},{"bank_alias":"昆明市呈贡区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009432"},{"bank_alias":"山东临沂兰山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009436"},{"bank_alias":"山东泗水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009439"},{"bank_alias":"黑龙江延寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009440"},{"bank_alias":"琼海市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009441"},{"bank_alias":"高邑县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009442"},{"bank_alias":"海南文昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009443"},{"bank_alias":"黑龙江呼玛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009444"},{"bank_alias":"石家庄市栾城农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009445"},{"bank_alias":"墨玉县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009446"},{"bank_alias":"云南宁蒗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009448"},{"bank_alias":"黑龙江省龙江县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009449"},{"bank_alias":"本溪市市区牛心台农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009455"},{"bank_alias":"九江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009458"},{"bank_alias":"云南昌宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009459"},{"bank_alias":"湖北巴东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009466"},{"bank_alias":"建宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009471"},{"bank_alias":"云南罗平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009473"},{"bank_alias":"阿坝县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009475"},{"bank_alias":"高阳县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009477"},{"bank_alias":"江西铅山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009479"},{"bank_alias":"山东高唐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009482"},{"bank_alias":"乌恰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009483"},{"bank_alias":"湖北汉川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009484"},{"bank_alias":"保定市清苑区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009485"},{"bank_alias":"海南白沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009490"},{"bank_alias":"石家庄汇融农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009491"},{"bank_alias":"江苏苏宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009493"},{"bank_alias":"温州民商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009494"},{"bank_alias":"深圳前海微众银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009495"},{"bank_alias":"重庆富民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009496"},{"bank_alias":"福建华通银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009499"},{"bank_alias":"无锡锡商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009500"},{"bank_alias":"浙江网商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009501"},{"bank_alias":"江西裕民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009502"},{"bank_alias":"武汉众邦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009504"},{"bank_alias":"天津金城银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009506"},{"bank_alias":"辽宁振兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009507"},{"bank_alias":"上海华瑞银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009508"},{"bank_alias":"四川新网银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009510"},{"bank_alias":"梅州客商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009511"},{"bank_alias":"营口经济技术开发区熊岳城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009512"},{"bank_alias":"盖州市城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009513"},{"bank_alias":"盖州市城市建设信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009514"},{"bank_alias":"盖州市辰州城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009515"},{"bank_alias":"大西洋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009516"},{"bank_alias":"印度尼西亚曼底利银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009517"},{"bank_alias":"台湾中小企业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009518"},{"bank_alias":"西班牙对外银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009519"},{"bank_alias":"巴基斯坦哈比银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009520"},{"bank_alias":"澳门国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009521"},{"bank_alias":"泰国汇商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009522"},{"bank_alias":"大丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009523"},{"bank_alias":"澳大利亚澳洲联邦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009524"},{"bank_alias":"韩国大邱银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009525"},{"bank_alias":"荷兰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009526"},{"bank_alias":"日本名古屋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009527"},{"bank_alias":"韩国釜山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009528"},{"bank_alias":"永丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009529"},{"bank_alias":"马来西亚联昌银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009530"},{"bank_alias":"中国信托商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009531"},{"bank_alias":"浦发硅谷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009532"},{"bank_alias":"埃及国民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009533"},{"bank_alias":"盘锦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009534"},{"bank_alias":"长治市上党区泰都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009536"},{"bank_alias":"晋中市太谷兴泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009537"},{"bank_alias":"黑龙江省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009542"},{"bank_alias":"安顺市平坝区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009544"},{"bank_alias":"云南澄江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009545"},{"bank_alias":"新疆布尔津喀纳斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009546"},{"bank_alias":"国家开发银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009551"},{"bank_alias":"中国进出口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009552"},{"bank_alias":"中国农业发展银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009553"},{"bank_alias":"恒丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009564"},{"bank_alias":"浙商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009565"},{"bank_alias":"渤海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009566"},{"bank_alias":"重庆三峡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009567"},{"bank_alias":"上海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009568"},{"bank_alias":"汇丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009572"},{"bank_alias":"东亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009573"},{"bank_alias":"恒生银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009575"},{"bank_alias":"集友银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009576"},{"bank_alias":"创兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009577"},{"bank_alias":"大众银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009578"},{"bank_alias":"上海商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009579"},{"bank_alias":"招商永隆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009580"},{"bank_alias":"大新银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009581"},{"bank_alias":"华南商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009582"},{"bank_alias":"彰银商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009583"},{"bank_alias":"国泰世华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009584"},{"bank_alias":"合作金库商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009585"},{"bank_alias":"第一商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009586"},{"bank_alias":"台湾土地银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009587"},{"bank_alias":"兆丰国际商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009588"},{"bank_alias":"台湾银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009589"},{"bank_alias":"玉山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009590"},{"bank_alias":"美国银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009592"},{"bank_alias":"美国建东银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009594"},{"bank_alias":"印度国家银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009595"},{"bank_alias":"三菱日联银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009596"},{"bank_alias":"三井住友银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009597"},{"bank_alias":"瑞穗银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009598"},{"bank_alias":"日本山口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009599"},{"bank_alias":"日本三井住友信托银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009600"},{"bank_alias":"日本横滨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009601"},{"bank_alias":"友利银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009602"},{"bank_alias":"韩国产业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009603"},{"bank_alias":"新韩银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009604"},{"bank_alias":"韩亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009606"},{"bank_alias":"国民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009607"},{"bank_alias":"马来西亚马来亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009608"},{"bank_alias":"首都银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009609"},{"bank_alias":"华侨永亨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009610"},{"bank_alias":"大华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009611"},{"bank_alias":"盘谷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009613"},{"bank_alias":"泰国泰京银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009614"},{"bank_alias":"开泰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009615"},{"bank_alias":"奥地利奥合国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009616"},{"bank_alias":"比利时联合银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009617"},{"bank_alias":"荷兰安智银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009618"},{"bank_alias":"英国巴克莱银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009620"},{"bank_alias":"瑞典北欧斯安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009622"},{"bank_alias":"瑞典银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009623"},{"bank_alias":"法国兴业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009624"},{"bank_alias":"法国外贸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009626"},{"bank_alias":"德意志银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009627"},{"bank_alias":"德国商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009628"},{"bank_alias":"德国北德意志州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009629"},{"bank_alias":"中德住房储蓄银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009630"},{"bank_alias":"意大利裕信银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009631"},{"bank_alias":"意大利联合圣保罗银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009632"},{"bank_alias":"瑞士信贷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009633"},{"bank_alias":"瑞士银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009634"},{"bank_alias":"加拿大丰业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009635"},{"bank_alias":"蒙特利尔银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009636"},{"bank_alias":"澳大利亚和新西兰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009637"},{"bank_alias":"澳大利亚西太平洋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009638"},{"bank_alias":"西班牙桑坦德银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009639"},{"bank_alias":"俄罗斯外贸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009640"},{"bank_alias":"摩根士丹利国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009641"},{"bank_alias":"华美银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009642"},{"bank_alias":"荷兰合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009643"},{"bank_alias":"厦门国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009644"},{"bank_alias":"华商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009646"},{"bank_alias":"富邦华一银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009647"},{"bank_alias":"网联清算有限公司","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009648"},{"bank_alias":"挪威银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009649"},{"bank_alias":"新联商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009650"},{"bank_alias":"徽商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009667"},{"bank_alias":"北京昌平发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009669"},{"bank_alias":"达尔罕茂明安联合旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009670"},{"bank_alias":"鄂温克蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009671"},{"bank_alias":"福建松溪长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009672"},{"bank_alias":"福建永泰长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009674"},{"bank_alias":"甘孜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009675"},{"bank_alias":"固阳蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009676"},{"bank_alias":"广元市发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009684"},{"bank_alias":"贵州册亨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009685"},{"bank_alias":"贵州剑河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009686"},{"bank_alias":"贵州望谟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009687"},{"bank_alias":"湖北荆门掇刀德通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009690"},{"bank_alias":"湖南绥宁湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009691"},{"bank_alias":"化德蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009692"},{"bank_alias":"江苏丹阳苏银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009693"},{"bank_alias":"江西万载富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009694"},{"bank_alias":"鄄城牡丹村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009695"},{"bank_alias":"芦山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009696"},{"bank_alias":"漯河市郾城发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009697"},{"bank_alias":"莫力达瓦蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009699"},{"bank_alias":"南通如皋润泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009701"},{"bank_alias":"内蒙古和林格尔蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009703"},{"bank_alias":"宁城蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009705"},{"bank_alias":"宁夏红寺堡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009706"},{"bank_alias":"宁夏隆德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009707"},{"bank_alias":"祁东惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009708"},{"bank_alias":"秦皇岛市抚宁农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009709"},{"bank_alias":"陕西榆林农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009717"},{"bank_alias":"四川江油农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009719"},{"bank_alias":"四川旺苍农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009720"},{"bank_alias":"四川银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009721"},{"bank_alias":"乌兰察布市集宁蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009722"},{"bank_alias":"乌审旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009723"},{"bank_alias":"武冈发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009724"},{"bank_alias":"西平中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009725"},{"bank_alias":"西乌珠穆沁蒙商惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009726"},{"bank_alias":"息烽发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009727"},{"bank_alias":"新疆阿瓦提农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009728"},{"bank_alias":"新疆玛纳斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009729"},{"bank_alias":"新疆鄯善农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009730"},{"bank_alias":"兴安盟科尔沁蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009731"},{"bank_alias":"兴和蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009732"},{"bank_alias":"扬州仪征玉丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009734"},{"bank_alias":"云南麻栗坡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009735"},{"bank_alias":"云南双柏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009736"},{"bank_alias":"云南砚山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009737"},{"bank_alias":"准格尔旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009738"},{"bank_alias":"贵州习水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009739"},{"bank_alias":"山西蒲县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009740"},{"bank_alias":"浙江永康农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009741"},{"bank_alias":"云南孟连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009742"},{"bank_alias":"万年稻源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009743"},{"bank_alias":"广西武宣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009744"},{"bank_alias":"福建华安长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009745"},{"bank_alias":"福建邵武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009746"},{"bank_alias":"浙江东阳富富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009747"},{"bank_alias":"湖南江永湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009748"},{"bank_alias":"辽沈银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009749"},{"bank_alias":"万宁金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009750"},{"bank_alias":"广西宾阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009751"},{"bank_alias":"湖南新田湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009752"},{"bank_alias":"新疆新源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009753"},{"bank_alias":"福建连江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009754"},{"bank_alias":"湖南炎陵星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009755"},{"bank_alias":"青海海东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009756"},{"bank_alias":"山西霍州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009757"},{"bank_alias":"贵州镇宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009758"},{"bank_alias":"重庆开州泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009759"},{"bank_alias":"宁波甬城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009760"},{"bank_alias":"云南元阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009762"},{"bank_alias":"湖南桑植湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009763"},{"bank_alias":"杭州银行","need_bank_branch":false,"account_bank":"杭州银行","account_bank_code":1109,"bank_alias_code":"1000005307"},{"bank_alias":"无锡农村商业银行","need_bank_branch":false,"account_bank":"无锡农商行","account_bank_code":4031,"bank_alias_code":"1000007493"},{"bank_alias":"献县融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000005360"},{"bank_alias":"广东普宁汇成村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000005847"},{"bank_alias":"东营融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006028"},{"bank_alias":"遵化融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006089"},{"bank_alias":"汕头潮阳融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006134"},{"bank_alias":"龙川融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006229"},{"bank_alias":"饶平融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006296"},{"bank_alias":"广州黄埔融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006929"},{"bank_alias":"广东澄海潮商村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006934"},{"bank_alias":"广东吴川农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006951"},{"bank_alias":"广东连平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006952"},{"bank_alias":"广东翁源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006954"},{"bank_alias":"广东连山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006955"},{"bank_alias":"广东连州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006959"},{"bank_alias":"广东始兴农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006961"},{"bank_alias":"广东平远农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006965"},{"bank_alias":"珠海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006972"},{"bank_alias":"广东阳山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006976"},{"bank_alias":"广东兴宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006981"},{"bank_alias":"广东丰顺农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007005"},{"bank_alias":"广东化州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007012"},{"bank_alias":"广东佛冈农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007033"},{"bank_alias":"广东阳春农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007035"},{"bank_alias":"广东鹤山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007039"},{"bank_alias":"广东揭阳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007040"},{"bank_alias":"广东乐昌农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007054"},{"bank_alias":"广东揭东农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007059"},{"bank_alias":"广东徐闻农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007074"},{"bank_alias":"广东龙门农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007079"},{"bank_alias":"广东广宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007082"},{"bank_alias":"广东高州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007106"},{"bank_alias":"广东封开农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007113"},{"bank_alias":"广东信宜农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007116"},{"bank_alias":"广东新丰农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007126"},{"bank_alias":"广东遂溪农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007131"},{"bank_alias":"广东东源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007132"},{"bank_alias":"广东博罗农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007149"},{"bank_alias":"广东蕉岭农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007159"},{"bank_alias":"广东南澳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007202"},{"bank_alias":"广东英德农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007204"},{"bank_alias":"佛山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007229"},{"bank_alias":"广东清新农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007255"},{"bank_alias":"广东南海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007257"},{"bank_alias":"广东普宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007258"},{"bank_alias":"广东乳源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007265"},{"bank_alias":"广东陆河农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007277"},{"bank_alias":"广东和平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007278"},{"bank_alias":"广东大埔农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007297"},{"bank_alias":"广东惠东农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007301"},{"bank_alias":"广东河源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007304"},{"bank_alias":"惠州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007312"},{"bank_alias":"广东南雄农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007314"},{"bank_alias":"广东紫金农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007326"},{"bank_alias":"韶关农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007331"},{"bank_alias":"广东仁化农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007345"},{"bank_alias":"广东揭西农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007348"},{"bank_alias":"广东德庆农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007349"},{"bank_alias":"广东廉江农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007363"},{"bank_alias":"湛江农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007367"},{"bank_alias":"广东开平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007386"},{"bank_alias":"广东陆丰农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007392"},{"bank_alias":"广东阳西农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007404"},{"bank_alias":"中山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007405"},{"bank_alias":"广东新兴农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007408"},{"bank_alias":"广东龙川农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007411"},{"bank_alias":"江门农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007417"},{"bank_alias":"广东怀集农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007424"},{"bank_alias":"梅州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007444"},{"bank_alias":"广东五华农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007449"},{"bank_alias":"广东四会农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007461"},{"bank_alias":"广东罗定农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007464"},{"bank_alias":"广东清远农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007466"},{"bank_alias":"广东台山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007468"},{"bank_alias":"广东连南农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007473"},{"bank_alias":"肇庆农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007490"},{"bank_alias":"广东茂名农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007495"},{"bank_alias":"汕尾农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007506"},{"bank_alias":"广东雷州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007513"},{"bank_alias":"广东云浮农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009535"},{"bank_alias":"广东潮阳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009677"},{"bank_alias":"广东澄海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009678"},{"bank_alias":"广东惠来农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009679"},{"bank_alias":"广东郁南农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009680"},{"bank_alias":"汕头海湾农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009718"},{"bank_alias":"广东顺德农村商业银行","need_bank_branch":false,"account_bank":"顺德农商银行","account_bank_code":4036,"bank_alias_code":"1000007068"},{"bank_alias":"浙江泰隆商业银行","need_bank_branch":false,"account_bank":"浙江泰隆商业银行","account_bank_code":4051,"bank_alias_code":"1000005310"},{"bank_alias":"宁波鄞州农村商业银行","need_bank_branch":false,"account_bank":"宁波鄞州农村商业银行","account_bank_code":4052,"bank_alias_code":"1000009163"},{"bank_alias":"邵武刺桐红村镇银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000005703"},{"bank_alias":"寿宁刺桐红村镇银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000006187"},{"bank_alias":"福建三明农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007075"},{"bank_alias":"福建南平农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007263"},{"bank_alias":"泉州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007296"},{"bank_alias":"福建上杭农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007302"},{"bank_alias":"福建永安农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007400"},{"bank_alias":"福建漳州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007426"},{"bank_alias":"福建安溪农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007465"},{"bank_alias":"福建石狮农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007475"},{"bank_alias":"福建福州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007479"},{"bank_alias":"福建莆田农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007502"},{"bank_alias":"柘荣县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007557"},{"bank_alias":"闽清县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007569"},{"bank_alias":"漳浦县农村信用社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007598"},{"bank_alias":"霞浦县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007666"},{"bank_alias":"长汀县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007719"},{"bank_alias":"泰宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007756"},{"bank_alias":"平和县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007769"},{"bank_alias":"永春县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007772"},{"bank_alias":"诏安县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007820"},{"bank_alias":"松溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007874"},{"bank_alias":"政和县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007907"},{"bank_alias":"仙游县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007938"},{"bank_alias":"连城县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007945"},{"bank_alias":"顺昌县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007957"},{"bank_alias":"周宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008009"},{"bank_alias":"清流县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008132"},{"bank_alias":"邵武市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008139"},{"bank_alias":"长泰县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008184"},{"bank_alias":"福建长乐农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008237"},{"bank_alias":"福建南安农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008276"},{"bank_alias":"古田县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008315"},{"bank_alias":"安溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008328"},{"bank_alias":"德化县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008329"},{"bank_alias":"尤溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008359"},{"bank_alias":"福建漳平农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008385"},{"bank_alias":"东山县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008495"},{"bank_alias":"福建建瓯农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008557"},{"bank_alias":"南靖县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008594"},{"bank_alias":"龙岩市永定区农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008618"},{"bank_alias":"明溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008620"},{"bank_alias":"福鼎市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008626"},{"bank_alias":"寿宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008667"},{"bank_alias":"福建宁德农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008705"},{"bank_alias":"福建龙岩农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008750"},{"bank_alias":"罗源县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008761"},{"bank_alias":"屏南县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008768"},{"bank_alias":"永泰县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008855"},{"bank_alias":"福建武夷山农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008913"},{"bank_alias":"宁化县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008943"},{"bank_alias":"福安市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008993"},{"bank_alias":"武平县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009018"},{"bank_alias":"闽侯县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009070"},{"bank_alias":"福建龙海农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009080"},{"bank_alias":"福建福清汇通农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009082"},{"bank_alias":"漳浦县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009103"},{"bank_alias":"永安市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009120"},{"bank_alias":"南平市建阳区农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009232"},{"bank_alias":"云霄县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009272"},{"bank_alias":"厦门农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009322"},{"bank_alias":"光泽县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009373"},{"bank_alias":"福建晋江农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009374"},{"bank_alias":"福建沙县农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009375"},{"bank_alias":"连江县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009406"},{"bank_alias":"浦城县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009481"},{"bank_alias":"福建平潭农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009489"},{"bank_alias":"福建仙游农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009673"},{"bank_alias":"南平农商银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009700"},{"bank_alias":"江苏紫金农村商业银行","need_bank_branch":false,"account_bank":"江苏紫金农村商业银行","account_bank_code":4072,"bank_alias_code":"1000007083"},{"bank_alias":"江苏紫金农商行","need_bank_branch":false,"account_bank":"江苏紫金农村商业银行","account_bank_code":4072,"bank_alias_code":"1000007289"},{"bank_alias":"深圳农村商业银行","need_bank_branch":false,"account_bank":"深圳农村商业银行","account_bank_code":4076,"bank_alias_code":"1000008173"},{"bank_alias":"西安鄠邑农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007158"},{"bank_alias":"陕西周至农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007195"},{"bank_alias":"陕西蓝田农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007233"},{"bank_alias":"陕西秦农农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007240"},{"bank_alias":"黄陵县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007543"},{"bank_alias":"西安市长安区太乙宫农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007548"},{"bank_alias":"西安市长安区鸣犊农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007549"},{"bank_alias":"陕西旬阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007578"},{"bank_alias":"陕西靖边农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007580"},{"bank_alias":"陕西石泉农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007583"},{"bank_alias":"宜君县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007597"},{"bank_alias":"陕西岚皋农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007606"},{"bank_alias":"泾阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007629"},{"bank_alias":"洛南县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007632"},{"bank_alias":"陕西汉阴农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007659"},{"bank_alias":"铜川市印台区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007714"},{"bank_alias":"陕西洛川农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007737"},{"bank_alias":"蒲城县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007773"},{"bank_alias":"洋县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007824"},{"bank_alias":"陕西眉县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007844"},{"bank_alias":"陕西吴堡农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007871"},{"bank_alias":"渭南市临渭区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007876"},{"bank_alias":"陕西佳县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007884"},{"bank_alias":"陕西镇坪农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007894"},{"bank_alias":"城固县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007896"},{"bank_alias":"西安市长安区五台农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007904"},{"bank_alias":"略阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007914"},{"bank_alias":"陕西丹凤农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007925"},{"bank_alias":"陕西南郑农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007968"},{"bank_alias":"黄龙县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007971"},{"bank_alias":"陕西彬州农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007972"},{"bank_alias":"西安市长安区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007979"},{"bank_alias":"西安市长安区纪阳农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007984"},{"bank_alias":"宝鸡市陈仓区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008021"},{"bank_alias":"延长县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008053"},{"bank_alias":"汉中市汉台区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008060"},{"bank_alias":"陕西岐山农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008088"},{"bank_alias":"富平县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008104"},{"bank_alias":"陕西清涧农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008105"},{"bank_alias":"西安市长安区内苑农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008115"},{"bank_alias":"华阴市农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008138"},{"bank_alias":"陕西子洲农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008157"},{"bank_alias":"陕西咸阳渭城农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008203"},{"bank_alias":"大荔县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008236"},{"bank_alias":"陕西宁陕农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008243"},{"bank_alias":"乾县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008246"},{"bank_alias":"陕西千阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008284"},{"bank_alias":"陕西吴起农村合作银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008285"},{"bank_alias":"陕西西乡农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008314"},{"bank_alias":"旬邑县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008319"},{"bank_alias":"西安市长安区杜陵农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008330"},{"bank_alias":"陕西山阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008350"},{"bank_alias":"宁强县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008380"},{"bank_alias":"兴平市农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008427"},{"bank_alias":"陕西镇安农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008439"},{"bank_alias":"陕西横山农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008441"},{"bank_alias":"西安市长安区王曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008457"},{"bank_alias":"西安市长安区细柳农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008492"},{"bank_alias":"陕西咸阳秦都农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008503"},{"bank_alias":"渭南市华州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008507"},{"bank_alias":"陕西府谷农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008545"},{"bank_alias":"铜川市耀州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008566"},{"bank_alias":"延安农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008569"},{"bank_alias":"陕西柞水农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008603"},{"bank_alias":"西安市长安区东大农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008622"},{"bank_alias":"陕西陇县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008684"},{"bank_alias":"礼泉县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008741"},{"bank_alias":"陕西绥德农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008767"},{"bank_alias":"合阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008775"},{"bank_alias":"延川县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008779"},{"bank_alias":"志丹县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008791"},{"bank_alias":"陕西平利农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008809"},{"bank_alias":"陕西神木农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008827"},{"bank_alias":"西安市长安区马王农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008845"},{"bank_alias":"陕西宝鸡金台农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008863"},{"bank_alias":"勉县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008868"},{"bank_alias":"陕西宝鸡渭滨农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008882"},{"bank_alias":"西安市长安区申店农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008888"},{"bank_alias":"西安市长安区滦镇农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008891"},{"bank_alias":"陕西商南农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008899"},{"bank_alias":"陕西麟游农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008900"},{"bank_alias":"陕西长武农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008911"},{"bank_alias":"陕西彬县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008914"},{"bank_alias":"三原县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008923"},{"bank_alias":"陕西甘泉农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008935"},{"bank_alias":"陕西韩城农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008977"},{"bank_alias":"陕西凤翔农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008999"},{"bank_alias":"潼关县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009002"},{"bank_alias":"西安市长安区韦曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009003"},{"bank_alias":"西安市长安区引镇农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009011"},{"bank_alias":"扶风县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009034"},{"bank_alias":"陕西杨凌农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009066"},{"bank_alias":"陕西子长农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009127"},{"bank_alias":"西安市长安区郭杜农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009128"},{"bank_alias":"西安市长安区五星农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009144"},{"bank_alias":"永寿县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009180"},{"bank_alias":"西安市长安区王莽农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009194"},{"bank_alias":"陕西安塞农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009210"},{"bank_alias":"留坝县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009233"},{"bank_alias":"陕西凤县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009237"},{"bank_alias":"陕西紫阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009241"},{"bank_alias":"陕西省农村信用社联合社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009246"},{"bank_alias":"白水县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009277"},{"bank_alias":"西安市长安区城区农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009278"},{"bank_alias":"商洛市商州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009306"},{"bank_alias":"西安市长安区大兆农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009313"},{"bank_alias":"陕西镇巴农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009318"},{"bank_alias":"西安市长安区斗门农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009343"},{"bank_alias":"安康农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009346"},{"bank_alias":"陕西定边农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009385"},{"bank_alias":"陕西富县农村合作银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009392"},{"bank_alias":"铜川市王益区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009410"},{"bank_alias":"武功县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009413"},{"bank_alias":"淳化县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009415"},{"bank_alias":"陕西白河农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009425"},{"bank_alias":"西安市长安区子午农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009437"},{"bank_alias":"宜川县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009438"},{"bank_alias":"陕西米脂农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009452"},{"bank_alias":"澄城县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009456"},{"bank_alias":"陕西太白农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009476"},{"bank_alias":"西安市长安区杜曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009486"},{"bank_alias":"西安市长安区农村信用合作社联合社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009488"},{"bank_alias":"陕西佛坪农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009716"},{"bank_alias":"北京农村商业银行","need_bank_branch":false,"account_bank":"北京农村商业银行","account_bank_code":4112,"bank_alias_code":"1000008612"},{"bank_alias":"广西象州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007530"},{"bank_alias":"广西西林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007540"},{"bank_alias":"广西天等农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007551"},{"bank_alias":"广西资源农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007585"},{"bank_alias":"南宁市武鸣区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007592"},{"bank_alias":"广西临桂农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007594"},{"bank_alias":"广西扶绥农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007622"},{"bank_alias":"玉林市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007655"},{"bank_alias":"广西灵川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007667"},{"bank_alias":"博白县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007678"},{"bank_alias":"广西永福农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007699"},{"bank_alias":"防城港市防城区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007704"},{"bank_alias":"广西靖西农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007734"},{"bank_alias":"广西蒙山农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007754"},{"bank_alias":"广西田阳农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007801"},{"bank_alias":"梧州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007810"},{"bank_alias":"广西大新农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007827"},{"bank_alias":"广西壮族自治区农村信用社联合社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007834"},{"bank_alias":"广西凭祥农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007882"},{"bank_alias":"广西平果农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007897"},{"bank_alias":"广西宜州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007921"},{"bank_alias":"广西上林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007944"},{"bank_alias":"广西恭城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007946"},{"bank_alias":"广西龙州农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007986"},{"bank_alias":"广西隆林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008007"},{"bank_alias":"广西田林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008033"},{"bank_alias":"广西融安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008035"},{"bank_alias":"南宁市邕宁区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008037"},{"bank_alias":"广西东兴农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008073"},{"bank_alias":"天峨县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008075"},{"bank_alias":"广西凌云农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008090"},{"bank_alias":"大化瑶族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008094"},{"bank_alias":"广西龙胜农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008147"},{"bank_alias":"南丹县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008154"},{"bank_alias":"容县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008159"},{"bank_alias":"广西罗城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008172"},{"bank_alias":"广西巴马农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008211"},{"bank_alias":"北海市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008226"},{"bank_alias":"广西乐业农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008268"},{"bank_alias":"广西浦北农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008274"},{"bank_alias":"广西平乐农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008287"},{"bank_alias":"广西兴安农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008342"},{"bank_alias":"广西鹿寨农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008353"},{"bank_alias":"环江毛南族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008403"},{"bank_alias":"广西融水农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008437"},{"bank_alias":"藤县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008455"},{"bank_alias":"广西柳江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008466"},{"bank_alias":"广西灌阳农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008586"},{"bank_alias":"河池市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008614"},{"bank_alias":"广西那坡农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008624"},{"bank_alias":"合山市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008665"},{"bank_alias":"广西田东农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008672"},{"bank_alias":"凤山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008691"},{"bank_alias":"三江侗族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008697"},{"bank_alias":"广西百色右江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008711"},{"bank_alias":"兴业县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008717"},{"bank_alias":"广西荔浦农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008735"},{"bank_alias":"广西岑溪农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008781"},{"bank_alias":"广西马山农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008812"},{"bank_alias":"柳州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008834"},{"bank_alias":"广西阳朔农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008856"},{"bank_alias":"广西桂林漓江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008884"},{"bank_alias":"桂平市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008898"},{"bank_alias":"忻城县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008924"},{"bank_alias":"灵山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008926"},{"bank_alias":"南宁市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008933"},{"bank_alias":"广西上思农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008934"},{"bank_alias":"广西陆川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008954"},{"bank_alias":"德保县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008959"},{"bank_alias":"广西全州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008964"},{"bank_alias":"广西昭平农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008983"},{"bank_alias":"广西柳城农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009112"},{"bank_alias":"防城港市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009115"},{"bank_alias":"广西贺州桂东农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009136"},{"bank_alias":"广西崇左桂南农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009187"},{"bank_alias":"东兰县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009209"},{"bank_alias":"广西富川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009219"},{"bank_alias":"广西宁明农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009244"},{"bank_alias":"钟山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009311"},{"bank_alias":"北流市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009316"},{"bank_alias":"广西来宾桂中农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009363"},{"bank_alias":"横县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009391"},{"bank_alias":"广西隆安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009424"},{"bank_alias":"平南县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009428"},{"bank_alias":"钦州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009434"},{"bank_alias":"合浦县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009454"},{"bank_alias":"广西金秀农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009543"},{"bank_alias":"广西苍梧农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009681"},{"bank_alias":"广西都安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009682"},{"bank_alias":"广西贵港荷城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009683"},{"bank_alias":"三门峡陕州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007528"},{"bank_alias":"河南林州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007536"},{"bank_alias":"河南南乐农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007584"},{"bank_alias":"河南杞县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007626"},{"bank_alias":"河南尉氏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007644"},{"bank_alias":"河南内乡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007645"},{"bank_alias":"河南邓州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007650"},{"bank_alias":"南阳市宛城区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007668"},{"bank_alias":"河南中牟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007677"},{"bank_alias":"郸城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007693"},{"bank_alias":"郑州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007709"},{"bank_alias":"平顶山市石龙区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007710"},{"bank_alias":"驻马店农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007746"},{"bank_alias":"河南汤阴农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007748"},{"bank_alias":"河南淮滨农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007767"},{"bank_alias":"河南汝南农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007786"},{"bank_alias":"河南长垣农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007848"},{"bank_alias":"河南汝阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007853"},{"bank_alias":"河南西峡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007869"},{"bank_alias":"河南平舆农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007892"},{"bank_alias":"洛阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007902"},{"bank_alias":"许昌农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007917"},{"bank_alias":"河南永城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007931"},{"bank_alias":"河南襄城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007943"},{"bank_alias":"河南新郑农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007987"},{"bank_alias":"河南博爱农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008010"},{"bank_alias":"河南叶县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008026"},{"bank_alias":"信阳市浉河区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008028"},{"bank_alias":"舞阳县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008057"},{"bank_alias":"河南民权农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008071"},{"bank_alias":"河南渑池农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008078"},{"bank_alias":"虞城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008103"},{"bank_alias":"河南桐柏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008116"},{"bank_alias":"睢县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008145"},{"bank_alias":"信阳市平桥区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008149"},{"bank_alias":"南阳市卧龙区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008158"},{"bank_alias":"临颍县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008163"},{"bank_alias":"新乡市凤泉区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008164"},{"bank_alias":"河南卢氏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008177"},{"bank_alias":"河南宜阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008179"},{"bank_alias":"三门峡湖滨农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008180"},{"bank_alias":"温县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008204"},{"bank_alias":"河南延津农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008215"},{"bank_alias":"河南潢川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008225"},{"bank_alias":"河南镇平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008240"},{"bank_alias":"河南栾川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008261"},{"bank_alias":"淇县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008269"},{"bank_alias":"焦作市山阳区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008271"},{"bank_alias":"河南太康农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008280"},{"bank_alias":"河南安阳商都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008296"},{"bank_alias":"河南嵩县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008300"},{"bank_alias":"焦作市马村区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008307"},{"bank_alias":"河南许昌许都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008313"},{"bank_alias":"方城县农村信用合作社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008340"},{"bank_alias":"河南舞钢农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008397"},{"bank_alias":"河南息县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008405"},{"bank_alias":"禹州市农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008431"},{"bank_alias":"河南确山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008434"},{"bank_alias":"河南登封农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008440"},{"bank_alias":"商丘华商农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008463"},{"bank_alias":"河南获嘉农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008469"},{"bank_alias":"河南新密农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008471"},{"bank_alias":"河南安阳相州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008478"},{"bank_alias":"河南固始农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008502"},{"bank_alias":"河南范县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008510"},{"bank_alias":"河南罗山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008526"},{"bank_alias":"河南沈丘农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008536"},{"bank_alias":"河南淅川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008537"},{"bank_alias":"河南荥阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008565"},{"bank_alias":"河南孟州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008595"},{"bank_alias":"河南扶沟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008605"},{"bank_alias":"河南清丰农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008623"},{"bank_alias":"河南兰考农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008654"},{"bank_alias":"平顶山卫东农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008675"},{"bank_alias":"河南巩义农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008680"},{"bank_alias":"河南鄢陵农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008688"},{"bank_alias":"平顶山市新华区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008702"},{"bank_alias":"淮阳县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008704"},{"bank_alias":"河南滑县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008720"},{"bank_alias":"周口农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008725"},{"bank_alias":"河南省农村信用社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008727"},{"bank_alias":"内黄县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008746"},{"bank_alias":"河南浚县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008763"},{"bank_alias":"河南社旗农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008765"},{"bank_alias":"郏县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008770"},{"bank_alias":"鲁山县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008776"},{"bank_alias":"河南长葛农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008777"},{"bank_alias":"漯河市源汇区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008801"},{"bank_alias":"河南宝丰农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008825"},{"bank_alias":"鹤壁农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008835"},{"bank_alias":"河南偃师农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008861"},{"bank_alias":"河南沁阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008873"},{"bank_alias":"焦作市中站区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008876"},{"bank_alias":"河南鹿邑农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008894"},{"bank_alias":"河南泌阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008896"},{"bank_alias":"河南辉县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008902"},{"bank_alias":"河南新野农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008912"},{"bank_alias":"新乡县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008941"},{"bank_alias":"封丘县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008950"},{"bank_alias":"河南南召农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008953"},{"bank_alias":"河南上蔡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008961"},{"bank_alias":"河南原阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008968"},{"bank_alias":"河南孟津农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008970"},{"bank_alias":"河南台前农村商行银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008976"},{"bank_alias":"河南商水农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009028"},{"bank_alias":"夏邑县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009046"},{"bank_alias":"河南新蔡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009051"},{"bank_alias":"漯河市郾城区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009056"},{"bank_alias":"河南洛宁农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009075"},{"bank_alias":"河南义马农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009107"},{"bank_alias":"宁陵县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009108"},{"bank_alias":"河南新安农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009113"},{"bank_alias":"河南西平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009122"},{"bank_alias":"河南灵宝农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009133"},{"bank_alias":"平顶山市市郊农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009157"},{"bank_alias":"河南正阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009162"},{"bank_alias":"西华县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009167"},{"bank_alias":"河南汴京农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009207"},{"bank_alias":"焦作解放农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009230"},{"bank_alias":"河南修武农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009261"},{"bank_alias":"河南柘城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009299"},{"bank_alias":"河南济源农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009331"},{"bank_alias":"信阳市明港农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009335"},{"bank_alias":"河南汝州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009341"},{"bank_alias":"唐河县农村信用合作社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009347"},{"bank_alias":"河南项城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009350"},{"bank_alias":"濮阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009360"},{"bank_alias":"漯河市召陵区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009364"},{"bank_alias":"商城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009384"},{"bank_alias":"河南伊川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009390"},{"bank_alias":"河南新县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009395"},{"bank_alias":"河南光山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009396"},{"bank_alias":"河南通许农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009405"},{"bank_alias":"开封宋都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009408"},{"bank_alias":"河南武陟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009429"},{"bank_alias":"河南遂平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009469"},{"bank_alias":"河南新乡平原农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009487"},{"bank_alias":"河南濮阳开州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009688"},{"bank_alias":"河南卫辉农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009689"},{"bank_alias":"宁夏黄河农村商业银行","need_bank_branch":false,"account_bank":"宁夏黄河农村商业银行","account_bank_code":4150,"bank_alias_code":"1000008716"},{"bank_alias":"天津农村商业银行","need_bank_branch":false,"account_bank":"天津农村商业银行","account_bank_code":4153,"bank_alias_code":"1000008524"},{"bank_alias":"晋中开发区农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007529"},{"bank_alias":"山西省交口县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007542"},{"bank_alias":"太原市小店区亲贤农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007552"},{"bank_alias":"山西省吕梁市文水县城关第二农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007556"},{"bank_alias":"山西省临县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007596"},{"bank_alias":"山西侯马农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007605"},{"bank_alias":"山西阳城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007609"},{"bank_alias":"太原市晋源区姚村农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007627"},{"bank_alias":"长治潞州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007651"},{"bank_alias":"山西平遥农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007652"},{"bank_alias":"大同县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007674"},{"bank_alias":"晋城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007680"},{"bank_alias":"石楼县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007681"},{"bank_alias":"山西垣曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007682"},{"bank_alias":"太原市小店区黄陵农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007721"},{"bank_alias":"山西壶关农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007732"},{"bank_alias":"山西古交农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007744"},{"bank_alias":"山西省吕梁市文水县凤城农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007764"},{"bank_alias":"山西榆次农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007771"},{"bank_alias":"文水县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007775"},{"bank_alias":"山西闻喜农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007778"},{"bank_alias":"山西芮城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007790"},{"bank_alias":"山西稷山农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007817"},{"bank_alias":"山西河津农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007828"},{"bank_alias":"山西山阴农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007858"},{"bank_alias":"山西孝义农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007872"},{"bank_alias":"山西省汾阳市三泉农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007910"},{"bank_alias":"山西左权农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007913"},{"bank_alias":"山西怀仁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007922"},{"bank_alias":"山西运城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007933"},{"bank_alias":"山西省石楼县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007941"},{"bank_alias":"山西洪洞农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007954"},{"bank_alias":"山西省吕梁市文水县城关第一农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007961"},{"bank_alias":"交口县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007976"},{"bank_alias":"山西省吕梁市中阳县金罗农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007989"},{"bank_alias":"山西省汾阳市冀村农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007994"},{"bank_alias":"山西沁水农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007996"},{"bank_alias":"太原市万柏林区后王农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008018"},{"bank_alias":"太原市晋源区金胜农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008020"},{"bank_alias":"太原市晋源区晋祠农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008066"},{"bank_alias":"山西安泽农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008070"},{"bank_alias":"太原市城区农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008117"},{"bank_alias":"太原市迎泽区郝庄农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008122"},{"bank_alias":"太原市万柏林区西铭农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008124"},{"bank_alias":"翼城县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008131"},{"bank_alias":"山西尧都农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008140"},{"bank_alias":"太原市晋源区晋源农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008146"},{"bank_alias":"山西省汾阳市城关农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008192"},{"bank_alias":"山西原平农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008193"},{"bank_alias":"山西泽州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008196"},{"bank_alias":"长治漳泽农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008202"},{"bank_alias":"山西省吕梁市交口县双池农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008223"},{"bank_alias":"山西长治黎都农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008232"},{"bank_alias":"山西襄垣农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008256"},{"bank_alias":"汾阳市农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008263"},{"bank_alias":"山西省方山县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008288"},{"bank_alias":"太原市娄烦县农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008299"},{"bank_alias":"山西省汾阳市农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008308"},{"bank_alias":"山西昔阳农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008317"},{"bank_alias":"太原市杏花岭区杨家峪农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008339"},{"bank_alias":"山西省太原市城区农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008341"},{"bank_alias":"山西省汾阳市文峰农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008343"},{"bank_alias":"山西繁峙农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008348"},{"bank_alias":"太原市杏花岭区中涧河农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008363"},{"bank_alias":"山西夏县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008365"},{"bank_alias":"山西灵丘农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008366"},{"bank_alias":"山西五台农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008371"},{"bank_alias":"山西岚县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008382"},{"bank_alias":"山西右玉农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008388"},{"bank_alias":"山西沁源农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008389"},{"bank_alias":"山西宁武农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008394"},{"bank_alias":"太原市小店区刘家堡农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008395"},{"bank_alias":"山西忻州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008425"},{"bank_alias":"山西高平农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008436"},{"bank_alias":"山西万荣农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008445"},{"bank_alias":"山西永和农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008452"},{"bank_alias":"山西省娄烦县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008465"},{"bank_alias":"山西永济农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008499"},{"bank_alias":"陵川县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008505"},{"bank_alias":"山西襄汾农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008515"},{"bank_alias":"山西省阳高县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008546"},{"bank_alias":"山西省吕梁市中阳县城关农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008550"},{"bank_alias":"太原市尖草坪区柴村农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008556"},{"bank_alias":"太原市小店区西温庄农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008558"},{"bank_alias":"山西浮山农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008574"},{"bank_alias":"山西省运城市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008575"},{"bank_alias":"山西省汾阳市阳城农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008587"},{"bank_alias":"山西省应县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008592"},{"bank_alias":"山西曲沃农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008607"},{"bank_alias":"中阳县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008621"},{"bank_alias":"山西岢岚农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008644"},{"bank_alias":"山西屯留农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008652"},{"bank_alias":"山西省广灵县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008694"},{"bank_alias":"山西省大同县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008708"},{"bank_alias":"山西乡宁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008713"},{"bank_alias":"太原市尖草坪区向阳农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008730"},{"bank_alias":"山西静乐农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008739"},{"bank_alias":"太原市小店区小店农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008753"},{"bank_alias":"太原市尖草坪区新城农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008782"},{"bank_alias":"山西和顺农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008787"},{"bank_alias":"太原市万柏林区东社农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008802"},{"bank_alias":"阳泉农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008848"},{"bank_alias":"山西柳林农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008869"},{"bank_alias":"山西大宁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008877"},{"bank_alias":"山西省吕梁市中阳县枝柯农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008879"},{"bank_alias":"山西武乡农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008883"},{"bank_alias":"山西兴县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008886"},{"bank_alias":"山西阳曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008893"},{"bank_alias":"山西平顺农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008930"},{"bank_alias":"山西绛县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008960"},{"bank_alias":"天镇县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008971"},{"bank_alias":"山西太谷农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008975"},{"bank_alias":"山西灵石农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008988"},{"bank_alias":"山西榆社农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009001"},{"bank_alias":"代县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009027"},{"bank_alias":"山西省汾阳市城西农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009043"},{"bank_alias":"山西省忻州市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009057"},{"bank_alias":"山西寿阳农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009058"},{"bank_alias":"朔州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009076"},{"bank_alias":"山西左云农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009084"},{"bank_alias":"山西清徐农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009087"},{"bank_alias":"山西潞城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009102"},{"bank_alias":"山西长子农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009118"},{"bank_alias":"山西省吕梁市文水县孝义农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009179"},{"bank_alias":"吕梁市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009197"},{"bank_alias":"太原市尖草坪区阳曲农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009212"},{"bank_alias":"山西盂县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009215"},{"bank_alias":"山西黎城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009218"},{"bank_alias":"山西省晋城市陵川县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009225"},{"bank_alias":"太原市万柏林区小井峪农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009226"},{"bank_alias":"太原市小店区朝阳农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009231"},{"bank_alias":"太原市小店区北格农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009270"},{"bank_alias":"山西省天镇县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009273"},{"bank_alias":"山西省朔州市应县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009308"},{"bank_alias":"山西介休农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009317"},{"bank_alias":"山西平陆农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009320"},{"bank_alias":"方山县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009321"},{"bank_alias":"山西沁县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009337"},{"bank_alias":"山西五寨农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009361"},{"bank_alias":"山西临猗农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009371"},{"bank_alias":"山西河曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009387"},{"bank_alias":"山西交城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009402"},{"bank_alias":"山西省吕梁市文水县开栅农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009411"},{"bank_alias":"山西神池农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009426"},{"bank_alias":"山西省中阳县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009435"},{"bank_alias":"太原市万柏林区沙沟农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009453"},{"bank_alias":"临县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009460"},{"bank_alias":"山西省代县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009468"},{"bank_alias":"大同农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009474"},{"bank_alias":"山西平定农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009538"},{"bank_alias":"山西定襄农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009539"},{"bank_alias":"山西古县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009540"},{"bank_alias":"山西隰县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009541"},{"bank_alias":"吕梁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009698"},{"bank_alias":"山西保德农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009710"},{"bank_alias":"山西浑源农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009711"},{"bank_alias":"山西吉县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009712"},{"bank_alias":"山西偏关农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009713"},{"bank_alias":"山西祁县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009714"},{"bank_alias":"山西新绛农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009715"},{"bank_alias":"武威农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006956"},{"bank_alias":"甘肃陇西农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006969"},{"bank_alias":"甘肃敦煌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006994"},{"bank_alias":"甘肃华亭农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006999"},{"bank_alias":"甘肃灵台农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007009"},{"bank_alias":"兰州农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007025"},{"bank_alias":"金昌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007030"},{"bank_alias":"甘肃玉门农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007072"},{"bank_alias":"平凉农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007088"},{"bank_alias":"甘肃静宁农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007111"},{"bank_alias":"甘肃民乐农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007114"},{"bank_alias":"甘肃礼县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007115"},{"bank_alias":"甘肃高台农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007136"},{"bank_alias":"甘肃古浪农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007162"},{"bank_alias":"甘肃临洮农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007166"},{"bank_alias":"甘肃泾川农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007178"},{"bank_alias":"酒泉农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007185"},{"bank_alias":"张掖农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007192"},{"bank_alias":"嘉峪关农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007199"},{"bank_alias":"甘肃西和农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007215"},{"bank_alias":"甘肃两当农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007234"},{"bank_alias":"甘肃会宁农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007260"},{"bank_alias":"甘肃秦安农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007280"},{"bank_alias":"甘肃康县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007320"},{"bank_alias":"甘肃天祝农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007337"},{"bank_alias":"庆阳农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007340"},{"bank_alias":"甘肃永昌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007342"},{"bank_alias":"甘肃山丹农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007360"},{"bank_alias":"甘肃靖远农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007368"},{"bank_alias":"临夏农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007381"},{"bank_alias":"甘肃瓜州农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007382"},{"bank_alias":"甘肃庄浪农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007391"},{"bank_alias":"甘肃崇信农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007403"},{"bank_alias":"定西农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007429"},{"bank_alias":"甘肃岷县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007501"},{"bank_alias":"甘肃临泽农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007514"},{"bank_alias":"甘肃民勤农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007518"},{"bank_alias":"玛曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007554"},{"bank_alias":"和政县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007560"},{"bank_alias":"甘谷县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007567"},{"bank_alias":"定西市通渭县鸡川信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007576"},{"bank_alias":"甘肃宁县农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007603"},{"bank_alias":"甘肃榆中农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007616"},{"bank_alias":"白银区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007619"},{"bank_alias":"甘肃省通渭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007654"},{"bank_alias":"皋兰县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007663"},{"bank_alias":"陇南武都农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007687"},{"bank_alias":"肃北蒙古族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007688"},{"bank_alias":"文县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007696"},{"bank_alias":"肃南裕固族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007733"},{"bank_alias":"天水秦州农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007738"},{"bank_alias":"通渭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007750"},{"bank_alias":"庆城县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007782"},{"bank_alias":"成县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007789"},{"bank_alias":"舟曲县城关农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007792"},{"bank_alias":"正宁县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007799"},{"bank_alias":"张家川回族自治县信用联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007805"},{"bank_alias":"徽县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007861"},{"bank_alias":"康乐县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007881"},{"bank_alias":"永靖县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007886"},{"bank_alias":"清水县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007901"},{"bank_alias":"白银市白银区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007948"},{"bank_alias":"张掖市肃南县皇城信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007950"},{"bank_alias":"卓尼县农村信用合作社联合社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007962"},{"bank_alias":"张家川回族自治县信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007981"},{"bank_alias":"东乡族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008048"},{"bank_alias":"景泰县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008110"},{"bank_alias":"肃南县农村信用联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008134"},{"bank_alias":"夏河县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008135"},{"bank_alias":"碌曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008137"},{"bank_alias":"天水麦积农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008176"},{"bank_alias":"舟曲县立节农村信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008198"},{"bank_alias":"舟曲县城关信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008201"},{"bank_alias":"金塔县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008221"},{"bank_alias":"定西市通渭县常河信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008327"},{"bank_alias":"定西市通渭县陇山信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008352"},{"bank_alias":"定西市漳县新寺信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008364"},{"bank_alias":"永登县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008387"},{"bank_alias":"玛曲县农村信用合作社联合社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008416"},{"bank_alias":"张家川回族自治县联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008438"},{"bank_alias":"合水县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008548"},{"bank_alias":"积石山县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008555"},{"bank_alias":"漳县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008559"},{"bank_alias":"华池县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008578"},{"bank_alias":"永靖县盐锅峡农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008601"},{"bank_alias":"张家川回族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008615"},{"bank_alias":"镇原县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008628"},{"bank_alias":"白银市平川区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008660"},{"bank_alias":"广河县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008662"},{"bank_alias":"甘肃省康乐县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008692"},{"bank_alias":"迭部县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008728"},{"bank_alias":"甘肃庄浪农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008732"},{"bank_alias":"宕昌县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008804"},{"bank_alias":"合作市农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008810"},{"bank_alias":"舟曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008829"},{"bank_alias":"临夏市农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008880"},{"bank_alias":"定西市通渭县义岗信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008887"},{"bank_alias":"临潭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008901"},{"bank_alias":"卓尼县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008965"},{"bank_alias":"积石山保安族东乡族撒拉族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008984"},{"bank_alias":"定西市漳县三岔信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008991"},{"bank_alias":"阿克塞哈萨克族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009014"},{"bank_alias":"武威市凉州区上泉农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009020"},{"bank_alias":"甘肃省渭源县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009062"},{"bank_alias":"天祝县藏族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009081"},{"bank_alias":"环县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009092"},{"bank_alias":"武山县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009096"},{"bank_alias":"舟曲县插岗农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009147"},{"bank_alias":"定西市通渭县榜罗信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009184"},{"bank_alias":"甘肃陇西农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009208"},{"bank_alias":"定西市通渭县城关信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009285"},{"bank_alias":"临夏县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009338"},{"bank_alias":"渭源县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009339"},{"bank_alias":"广河县三甲集农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009433"},{"bank_alias":"武威市凉州区下双农村信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009465"},{"bank_alias":"内蒙古太仆寺农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007526"},{"bank_alias":"包头农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007541"},{"bank_alias":"内蒙古五原农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007564"},{"bank_alias":"额济纳旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007572"},{"bank_alias":"巴彦淖尔河套农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007582"},{"bank_alias":"阿巴嘎旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007588"},{"bank_alias":"内蒙古自治区农村信用社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007595"},{"bank_alias":"内蒙古宁城农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007610"},{"bank_alias":"乌兰浩特市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007637"},{"bank_alias":"巴林右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007639"},{"bank_alias":"赤峰元宝山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007647"},{"bank_alias":"凉城县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007695"},{"bank_alias":"察哈尔右翼后旗农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007702"},{"bank_alias":"内蒙古阿尔山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007707"},{"bank_alias":"内蒙古伊金霍洛农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007708"},{"bank_alias":"和林格尔县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007723"},{"bank_alias":"额尔古纳市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007725"},{"bank_alias":"开鲁县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007741"},{"bank_alias":"内蒙古克什克腾农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007752"},{"bank_alias":"扎兰屯市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007779"},{"bank_alias":"通辽市科尔沁区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007788"},{"bank_alias":"武川县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007803"},{"bank_alias":"内蒙古西乌珠穆沁农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007806"},{"bank_alias":"内蒙古陕坝农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007821"},{"bank_alias":"翁牛特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007849"},{"bank_alias":"察哈尔右翼中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007855"},{"bank_alias":"科尔沁右翼前旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007865"},{"bank_alias":"和林格尔农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007875"},{"bank_alias":"巴林左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007888"},{"bank_alias":"东乌珠穆沁旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007889"},{"bank_alias":"镶黄旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007903"},{"bank_alias":"多伦县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007912"},{"bank_alias":"扎赉特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007932"},{"bank_alias":"满洲里农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007980"},{"bank_alias":"苏尼特右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008002"},{"bank_alias":"内蒙古察哈尔右翼前旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008056"},{"bank_alias":"苏尼特左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008085"},{"bank_alias":"陈巴尔虎旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008087"},{"bank_alias":"正蓝旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008127"},{"bank_alias":"内蒙古鄂托克前旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008171"},{"bank_alias":"内蒙古根河市好里堡农村信用合作社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008182"},{"bank_alias":"突泉县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008207"},{"bank_alias":"内蒙古阿鲁科尔沁农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008258"},{"bank_alias":"准格尔旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008279"},{"bank_alias":"二连浩特农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008337"},{"bank_alias":"准格尔煤田农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008392"},{"bank_alias":"阿拉善右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008421"},{"bank_alias":"阿荣旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008468"},{"bank_alias":"赤峰市红山区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008473"},{"bank_alias":"锡林浩特农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008474"},{"bank_alias":"内蒙古乌拉特农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008487"},{"bank_alias":"乌拉特后旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008488"},{"bank_alias":"霍林郭勒市农村信用合作社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008500"},{"bank_alias":"内蒙古牙克石农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008509"},{"bank_alias":"内蒙古土默特右旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008514"},{"bank_alias":"敖汉旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008599"},{"bank_alias":"内蒙古鄂伦春农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008642"},{"bank_alias":"科尔沁左翼后旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008653"},{"bank_alias":"内蒙古呼和浩特金谷农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008679"},{"bank_alias":"清水河县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008695"},{"bank_alias":"内蒙古乌兰察布市化德县农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008712"},{"bank_alias":"包头市南郊农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008715"},{"bank_alias":"乌兰察布农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008736"},{"bank_alias":"四子王旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008850"},{"bank_alias":"商都县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008917"},{"bank_alias":"固阳县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008928"},{"bank_alias":"达拉特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008931"},{"bank_alias":"丰镇市农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008937"},{"bank_alias":"喀喇沁旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008981"},{"bank_alias":"内蒙古鄂温克农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008987"},{"bank_alias":"兴和县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009005"},{"bank_alias":"内蒙古兴安盟科尔沁右翼中旗农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009007"},{"bank_alias":"土默特左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009038"},{"bank_alias":"内蒙古林西农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009040"},{"bank_alias":"莫力达瓦达斡尔族自治旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009042"},{"bank_alias":"内蒙古托克托农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009065"},{"bank_alias":"扎鲁特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009089"},{"bank_alias":"伊金霍洛旗矿区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009097"},{"bank_alias":"乌审旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009132"},{"bank_alias":"根河市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009161"},{"bank_alias":"内蒙古呼伦贝尔市新巴尔虎右旗农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009205"},{"bank_alias":"鄂尔多斯农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009220"},{"bank_alias":"正镶白旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009234"},{"bank_alias":"科尔沁左翼中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009247"},{"bank_alias":"土左旗察素齐信用社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009254"},{"bank_alias":"乌拉特中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009263"},{"bank_alias":"达尔罕茂明安联合旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009264"},{"bank_alias":"内蒙古鄂托克农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009290"},{"bank_alias":"新巴尔虎左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009348"},{"bank_alias":"呼伦贝尔农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009372"},{"bank_alias":"通辽奈曼农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009397"},{"bank_alias":"赤峰松山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009399"},{"bank_alias":"阿拉善农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009400"},{"bank_alias":"磴口县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009421"},{"bank_alias":"卓资县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009462"},{"bank_alias":"内蒙古杭锦农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009702"},{"bank_alias":"内蒙古库伦农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009704"},{"bank_alias":"安徽石台农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007571"},{"bank_alias":"安徽来安农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007615"},{"bank_alias":"安徽无为农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007660"},{"bank_alias":"安徽涡阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007697"},{"bank_alias":"安徽霍山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007715"},{"bank_alias":"安徽旌德农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007724"},{"bank_alias":"滁州皖东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007730"},{"bank_alias":"芜湖津盛农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007751"},{"bank_alias":"安徽宿州农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007796"},{"bank_alias":"安徽颍上农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007843"},{"bank_alias":"安徽固镇农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007852"},{"bank_alias":"安徽桐城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007885"},{"bank_alias":"安徽定远农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007890"},{"bank_alias":"亳州药都农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007951"},{"bank_alias":"安徽凤阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007975"},{"bank_alias":"阜阳颍东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007993"},{"bank_alias":"安徽庐江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008043"},{"bank_alias":"铜陵皖江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008069"},{"bank_alias":"安徽阜南农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008112"},{"bank_alias":"安徽临泉农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008119"},{"bank_alias":"铜陵农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008189"},{"bank_alias":"安徽歙县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008238"},{"bank_alias":"阜阳颍淮农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008247"},{"bank_alias":"安徽南陵农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008248"},{"bank_alias":"淮北农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008354"},{"bank_alias":"宣城皖南农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008370"},{"bank_alias":"安徽五河农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008398"},{"bank_alias":"黄山太平农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008404"},{"bank_alias":"池州九华农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008414"},{"bank_alias":"安徽马鞍山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008415"},{"bank_alias":"安徽舒城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008459"},{"bank_alias":"安徽岳西农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008461"},{"bank_alias":"安徽天长农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008490"},{"bank_alias":"安徽宿松农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008522"},{"bank_alias":"安徽绩溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008532"},{"bank_alias":"安徽太和农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008563"},{"bank_alias":"阜阳颍泉农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008576"},{"bank_alias":"六安农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008583"},{"bank_alias":"安徽枞阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008585"},{"bank_alias":"安徽界首农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008589"},{"bank_alias":"安徽黟县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008590"},{"bank_alias":"安徽肥东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008600"},{"bank_alias":"安徽怀远农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008611"},{"bank_alias":"安徽泾县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008619"},{"bank_alias":"黄山屯溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008625"},{"bank_alias":"安徽东至农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008635"},{"bank_alias":"蚌埠农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008666"},{"bank_alias":"安徽郎溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008676"},{"bank_alias":"安徽灵璧农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008683"},{"bank_alias":"安徽休宁农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008721"},{"bank_alias":"安徽全椒农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008772"},{"bank_alias":"安徽广德农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008798"},{"bank_alias":"安徽长丰农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008805"},{"bank_alias":"安徽砀山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008875"},{"bank_alias":"安徽泗县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008904"},{"bank_alias":"安徽省农村信用社联合社","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008915"},{"bank_alias":"安徽利辛农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008938"},{"bank_alias":"安徽祁门农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008949"},{"bank_alias":"安庆农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008972"},{"bank_alias":"安徽萧县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009077"},{"bank_alias":"安徽叶集农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009104"},{"bank_alias":"安徽和县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009138"},{"bank_alias":"合肥科技农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009170"},{"bank_alias":"巢湖农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009171"},{"bank_alias":"安徽濉溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009175"},{"bank_alias":"安徽繁昌农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009182"},{"bank_alias":"安徽肥西农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009201"},{"bank_alias":"安徽望江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009223"},{"bank_alias":"芜湖扬子农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009238"},{"bank_alias":"安徽宁国农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009239"},{"bank_alias":"安徽凤台农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009276"},{"bank_alias":"淮南淮河农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009283"},{"bank_alias":"安徽青阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009295"},{"bank_alias":"安徽明光农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009298"},{"bank_alias":"安徽怀宁农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009349"},{"bank_alias":"安徽霍邱农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009365"},{"bank_alias":"安徽太湖农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009368"},{"bank_alias":"安徽蒙城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009379"},{"bank_alias":"安徽寿县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009401"},{"bank_alias":"黄山徽州农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009403"},{"bank_alias":"淮南通商农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009447"},{"bank_alias":"安徽潜山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009464"},{"bank_alias":"安徽含山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009470"},{"bank_alias":"安徽金寨农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009472"},{"bank_alias":"天津滨海农村商业银行","need_bank_branch":false,"account_bank":"天津滨海农商行","account_bank_code":4169,"bank_alias_code":"1000007090"},{"bank_alias":"长沙银行","need_bank_branch":false,"account_bank":"长沙银行","account_bank_code":4216,"bank_alias_code":"1000005292"},{"bank_alias":"江苏靖江农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006962"},{"bank_alias":"江苏高邮农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006963"},{"bank_alias":"江苏如皋农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006967"},{"bank_alias":"江苏南通农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006983"},{"bank_alias":"江苏海安农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006991"},{"bank_alias":"江苏丹阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007006"},{"bank_alias":"江苏镇江农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007014"},{"bank_alias":"江苏淮安农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007015"},{"bank_alias":"连云港东方农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007016"},{"bank_alias":"江苏宜兴农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007024"},{"bank_alias":"江苏睢宁农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007032"},{"bank_alias":"江苏溧水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007041"},{"bank_alias":"江苏邳州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007048"},{"bank_alias":"江苏射阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007053"},{"bank_alias":"江苏赣榆农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007058"},{"bank_alias":"江苏东台农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007064"},{"bank_alias":"江苏建湖农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007069"},{"bank_alias":"江苏句容农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007109"},{"bank_alias":"江苏泗洪农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007135"},{"bank_alias":"江苏扬州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007139"},{"bank_alias":"江苏盱眙农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007165"},{"bank_alias":"江苏阜宁农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007183"},{"bank_alias":"江苏扬中农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007186"},{"bank_alias":"江苏如东农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007187"},{"bank_alias":"江苏泰州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007188"},{"bank_alias":"江苏洪泽农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007190"},{"bank_alias":"江苏新沂农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007201"},{"bank_alias":"江苏高淳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007208"},{"bank_alias":"江苏灌南农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007217"},{"bank_alias":"江苏丰县农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007261"},{"bank_alias":"江苏溧水农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007293"},{"bank_alias":"江苏宝应农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007295"},{"bank_alias":"江苏泗阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007299"},{"bank_alias":"江苏东海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007321"},{"bank_alias":"徐州彭城农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007322"},{"bank_alias":"江苏大丰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007323"},{"bank_alias":"江苏滨海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007332"},{"bank_alias":"江苏金湖农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007354"},{"bank_alias":"江苏宜兴农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007358"},{"bank_alias":"如皋农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007376"},{"bank_alias":"江苏姜堰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007384"},{"bank_alias":"江苏盐城农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007390"},{"bank_alias":"江苏仪征农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007394"},{"bank_alias":"江苏灌云农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007396"},{"bank_alias":"江苏启东农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007398"},{"bank_alias":"江苏江都农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007432"},{"bank_alias":"扬州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007443"},{"bank_alias":"江苏涟水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007451"},{"bank_alias":"江苏沭阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007460"},{"bank_alias":"溧水农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007463"},{"bank_alias":"江苏泰兴农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007471"},{"bank_alias":"江苏海门农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007476"},{"bank_alias":"徐州淮海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007480"},{"bank_alias":"江苏沛县农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007481"},{"bank_alias":"徐州铜山农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007482"},{"bank_alias":"江苏响水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007486"},{"bank_alias":"江苏兴化农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007499"},{"bank_alias":"江苏民丰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007510"},{"bank_alias":"徐州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000009733"},{"bank_alias":"湖州银行","need_bank_branch":false,"account_bank":"湖州银行","account_bank_code":4741,"bank_alias_code":"1000005300"},{"bank_alias":"哈密市商业银行","need_bank_branch":false,"account_bank":"哈密银行","account_bank_code":4750,"bank_alias_code":"1000005239"},{"bank_alias":"衡水银行","need_bank_branch":false,"account_bank":"衡水银行","account_bank_code":4752,"bank_alias_code":"1000005223"},{"bank_alias":"中原银行","need_bank_branch":false,"account_bank":"中原银行","account_bank_code":4753,"bank_alias_code":"1000005246"},{"bank_alias":"东营莱商村镇银行","need_bank_branch":false,"account_bank":"东营莱商村镇银行","account_bank_code":4754,"bank_alias_code":"1000005422"},{"bank_alias":"长子县融汇村镇银行","need_bank_branch":false,"account_bank":"长子县融汇村镇银行","account_bank_code":4755,"bank_alias_code":"1000005328"},{"bank_alias":"长治银行","need_bank_branch":false,"account_bank":"长治银行","account_bank_code":4756,"bank_alias_code":"1000005215"},{"bank_alias":"海口联合农村商业银行","need_bank_branch":false,"account_bank":"海口联合农商银行","account_bank_code":4758,"bank_alias_code":"1000007286"},{"bank_alias":"企业银行","need_bank_branch":false,"account_bank":"企业银行","account_bank_code":4761,"bank_alias_code":"1000009605"},{"bank_alias":"渣打银行","need_bank_branch":false,"account_bank":"渣打银行","account_bank_code":4762,"bank_alias_code":"1000009619"},{"bank_alias":"南洋商业银行","need_bank_branch":false,"account_bank":"南洋商业银行","account_bank_code":4763,"bank_alias_code":"1000009574"},{"bank_alias":"浙江上虞农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007527"},{"bank_alias":"浙江富阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007574"},{"bank_alias":"浙江瑞安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007587"},{"bank_alias":"浙江台州椒江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007602"},{"bank_alias":"浙江永康农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007608"},{"bank_alias":"浙江松阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007614"},{"bank_alias":"浙江德清农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007625"},{"bank_alias":"浙江兰溪农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007679"},{"bank_alias":"浙江诸暨农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007683"},{"bank_alias":"浙江桐庐农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007722"},{"bank_alias":"浙江景宁农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007785"},{"bank_alias":"浙江云和农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007819"},{"bank_alias":"宁波北仑农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007877"},{"bank_alias":"浙江龙泉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007952"},{"bank_alias":"浙江新昌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007974"},{"bank_alias":"浙江绍兴恒信农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008038"},{"bank_alias":"浙江台州路桥农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008047"},{"bank_alias":"浙江玉环农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008076"},{"bank_alias":"浙江建德农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008092"},{"bank_alias":"浙江海宁农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008129"},{"bank_alias":"浙江南浔农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008148"},{"bank_alias":"宁波镇海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008175"},{"bank_alias":"浙江东阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008190"},{"bank_alias":"浙江三门农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008194"},{"bank_alias":"浙江温州龙湾农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008220"},{"bank_alias":"浙江苍南农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008306"},{"bank_alias":"浙江台州黄岩农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008316"},{"bank_alias":"浙江金华成泰农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008333"},{"bank_alias":"浙江温州鹿城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008345"},{"bank_alias":"浙江天台农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008368"},{"bank_alias":"浙江舟山普陀农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008400"},{"bank_alias":"浙江淳安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008443"},{"bank_alias":"浙江临安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008458"},{"bank_alias":"宁波慈溪农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008475"},{"bank_alias":"浙江青田农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008539"},{"bank_alias":"浙江文成农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008540"},{"bank_alias":"浙江龙游农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008572"},{"bank_alias":"杭州联合农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008581"},{"bank_alias":"浙江安吉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008582"},{"bank_alias":"浙江禾城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008602"},{"bank_alias":"浙江开化农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008610"},{"bank_alias":"浙江温岭农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008651"},{"bank_alias":"浙江嵊泗农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008668"},{"bank_alias":"浙江温州洞头农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008674"},{"bank_alias":"舟山定海海洋农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008696"},{"bank_alias":"浙江缙云农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008703"},{"bank_alias":"浙江临海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008719"},{"bank_alias":"浙江常山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008731"},{"bank_alias":"浙江岱山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008740"},{"bank_alias":"浙江丽水莲都农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008744"},{"bank_alias":"浙江义乌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008783"},{"bank_alias":"象山县农村信用合作联社","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008790"},{"bank_alias":"浙江长兴农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008800"},{"bank_alias":"浙江海盐农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008803"},{"bank_alias":"浙江舟山定海海洋农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008836"},{"bank_alias":"浙江平湖农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008839"},{"bank_alias":"宁波余姚农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008859"},{"bank_alias":"浙江桐乡农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008916"},{"bank_alias":"浙江浦江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008922"},{"bank_alias":"浙江平阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008927"},{"bank_alias":"宁波奉化农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008951"},{"bank_alias":"浙江龙湾农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009004"},{"bank_alias":"浙江嵊州农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009025"},{"bank_alias":"浙江泰顺农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009061"},{"bank_alias":"浙江磐安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009098"},{"bank_alias":"浙江温州瓯海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009100"},{"bank_alias":"浙江绍兴瑞丰农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009119"},{"bank_alias":"浙江永嘉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009125"},{"bank_alias":"浙江乐清农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009135"},{"bank_alias":"浙江衢州衢江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009160"},{"bank_alias":"浙江遂昌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009165"},{"bank_alias":"浙江嘉善农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009178"},{"bank_alias":"浙江萧山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009183"},{"bank_alias":"浙江省农村信用社联合社","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009279"},{"bank_alias":"浙江武义农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009334"},{"bank_alias":"湖州吴兴农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009357"},{"bank_alias":"浙江仙居农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009450"},{"bank_alias":"浙江庆元农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009451"},{"bank_alias":"浙江江山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009457"},{"bank_alias":"浙江衢州柯城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009463"},{"bank_alias":"浙江杭州余杭农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009467"},{"bank_alias":"宁波宁海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009480"},{"bank_alias":"秦皇岛银行","need_bank_branch":false,"account_bank":"秦皇岛银行","account_bank_code":4765,"bank_alias_code":"1000005253"},{"bank_alias":"枣庄银行","need_bank_branch":false,"account_bank":"枣庄银行","account_bank_code":4766,"bank_alias_code":"1000005197"},{"bank_alias":"大同银行","need_bank_branch":false,"account_bank":"大同银行","account_bank_code":4767,"bank_alias_code":"1000005202"},{"bank_alias":"威海蓝海银行","need_bank_branch":false,"account_bank":"蓝海银行","account_bank_code":4768,"bank_alias_code":"1000009509"},{"bank_alias":"北京中关村银行","need_bank_branch":false,"account_bank":"北京中关村银行","account_bank_code":4769,"bank_alias_code":"1000009503"},{"bank_alias":"长城华西银行","need_bank_branch":false,"account_bank":"长城华西银行","account_bank_code":4773,"bank_alias_code":"1000005285"},{"bank_alias":"库尔勒银行","need_bank_branch":false,"account_bank":"库尔勒银行","account_bank_code":4774,"bank_alias_code":"1000005301"},{"bank_alias":"星展银行","need_bank_branch":false,"account_bank":"星展银行","account_bank_code":4778,"bank_alias_code":"1000009612"},{"bank_alias":"中信百信银行","need_bank_branch":false,"account_bank":"百信银行","account_bank_code":4779,"bank_alias_code":"1000009570"},{"bank_alias":"吉林亿联银行","need_bank_branch":false,"account_bank":"亿联银行","account_bank_code":4780,"bank_alias_code":"1000009497"},{"bank_alias":"青县青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005769"},{"bank_alias":"东阿青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005874"},{"bank_alias":"鱼台青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005956"},{"bank_alias":"东光青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005996"},{"bank_alias":"高唐青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006152"},{"bank_alias":"莘县青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006156"},{"bank_alias":"黄骅青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006469"},{"bank_alias":"沧州市运河青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006616"},{"bank_alias":"桓台青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006636"},{"bank_alias":"山东周村青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006762"},{"bank_alias":"山东邹平青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006921"},{"bank_alias":"长春南关惠民村镇银行","need_bank_branch":false,"account_bank":"长春南关惠民村镇银行","account_bank_code":4782,"bank_alias_code":"1000006425"},{"bank_alias":"湖北银行","need_bank_branch":false,"account_bank":"湖北银行","account_bank_code":4783,"bank_alias_code":"1000005272"},{"bank_alias":"齐河胶东村镇银行","need_bank_branch":false,"account_bank":"齐河胶东村镇银行","account_bank_code":4784,"bank_alias_code":"1000005677"},{"bank_alias":"南阳村镇银行","need_bank_branch":false,"account_bank":"南阳村镇银行","account_bank_code":4785,"bank_alias_code":"1000006018"},{"bank_alias":"湖南三湘银行","need_bank_branch":false,"account_bank":"三湘银行","account_bank_code":4787,"bank_alias_code":"1000009498"},{"bank_alias":"前郭县阳光村镇银行","need_bank_branch":false,"account_bank":"前郭县阳光村镇银行","account_bank_code":4788,"bank_alias_code":"1000006798"},{"bank_alias":"宁夏中宁青银村镇银行","need_bank_branch":false,"account_bank":"中宁青银村镇银行","account_bank_code":4789,"bank_alias_code":"1000005590"},{"bank_alias":"绥阳黔北村镇银行","need_bank_branch":false,"account_bank":"绥阳黔北村镇银行","account_bank_code":4790,"bank_alias_code":"1000006864"},{"bank_alias":"长春经开融丰村镇银行","need_bank_branch":false,"account_bank":"长春经开融丰村镇银行","account_bank_code":4791,"bank_alias_code":"1000005611"},{"bank_alias":"沙河襄通村镇银行","need_bank_branch":false,"account_bank":"沙河襄通村镇银行","account_bank_code":4794,"bank_alias_code":"1000005693"},{"bank_alias":"垦利乐安村镇银行","need_bank_branch":false,"account_bank":"垦利乐安村镇银行","account_bank_code":4795,"bank_alias_code":"1000006763"},{"bank_alias":"花旗银行","need_bank_branch":false,"account_bank":"花旗银行","account_bank_code":4796,"bank_alias_code":"1000009591"},{"bank_alias":"长春朝阳和润村镇银行","need_bank_branch":false,"account_bank":"长春朝阳和润村镇银行","account_bank_code":4797,"bank_alias_code":"1000006730"},{"bank_alias":"江苏银行","need_bank_branch":false,"account_bank":"江苏银行","account_bank_code":4830,"bank_alias_code":"1000005302"},{"bank_alias":"北京银行","need_bank_branch":false,"account_bank":"北京银行","account_bank_code":4836,"bank_alias_code":"1000005194"},{"bank_alias":"襄垣县融汇村镇银行","need_bank_branch":false,"account_bank":"襄垣县融汇村镇银行","account_bank_code":4842,"bank_alias_code":"1000006438"},{"bank_alias":"德州银行","need_bank_branch":false,"account_bank":"德州银行","account_bank_code":4843,"bank_alias_code":"1000005306"},{"bank_alias":"晋商银行","need_bank_branch":false,"account_bank":"晋商银行","account_bank_code":4844,"bank_alias_code":"1000005293"},{"bank_alias":"法国巴黎银行","need_bank_branch":false,"account_bank":"法国巴黎银行","account_bank_code":4845,"bank_alias_code":"1000009645"},{"bank_alias":"新疆绿洲国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005344"},{"bank_alias":"克拉玛依金龙国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005428"},{"bank_alias":"伊犁国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005506"},{"bank_alias":"平果国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005507"},{"bank_alias":"昌吉国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005640"},{"bank_alias":"广西银海国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005724"},{"bank_alias":"博乐国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005755"},{"bank_alias":"东兴国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005848"},{"bank_alias":"石河子国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005999"},{"bank_alias":"哈密红星国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006136"},{"bank_alias":"五家渠国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006274"},{"bank_alias":"库车国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006451"},{"bank_alias":"防城港防城国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006475"},{"bank_alias":"广西钦州市钦南国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006546"},{"bank_alias":"北屯国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006554"},{"bank_alias":"奎屯国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006585"},{"bank_alias":"广西浦北国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006681"},{"bank_alias":"广西上林国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006706"},{"bank_alias":"邛崃国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006753"},{"bank_alias":"宁波市海曙国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006806"},{"bank_alias":"合浦国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006816"},{"bank_alias":"象山国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006841"},{"bank_alias":"山东临朐聚丰村镇银行","need_bank_branch":false,"account_bank":"山东临朐聚丰村镇银行","account_bank_code":4864,"bank_alias_code":"1000006406"},{"bank_alias":"香河益民村镇银行","need_bank_branch":false,"account_bank":"香河益民村镇银行","account_bank_code":4865,"bank_alias_code":"1000006449"},{"bank_alias":"辽宁岫岩金玉村镇银行","need_bank_branch":false,"account_bank":"辽宁岫岩金玉村镇银行","account_bank_code":4866,"bank_alias_code":"1000006900"},{"bank_alias":"阳城县三禾村镇银行","need_bank_branch":false,"account_bank":"阳城县三禾村镇银行","account_bank_code":4867,"bank_alias_code":"1000005458"},{"bank_alias":"永济市三禾村镇银行","need_bank_branch":false,"account_bank":"永济市三禾村镇银行","account_bank_code":4868,"bank_alias_code":"1000006415"},{"bank_alias":"禹城胶东村镇银行","need_bank_branch":false,"account_bank":"禹城胶东村镇银行","account_bank_code":4869,"bank_alias_code":"1000005963"},{"bank_alias":"遵义播州汇隆村镇银行","need_bank_branch":false,"account_bank":"遵义播州汇隆村镇银行","account_bank_code":4870,"bank_alias_code":"1000006000"},{"bank_alias":"辽宁辰州汇通村镇银行","need_bank_branch":false,"account_bank":"辽宁辰州汇通村镇银行","account_bank_code":4871,"bank_alias_code":"1000005917"},{"bank_alias":"辽宁大石桥隆丰村镇银行","need_bank_branch":false,"account_bank":"辽宁大石桥隆丰村镇银行","account_bank_code":4872,"bank_alias_code":"1000006764"},{"bank_alias":"大洼恒丰村镇银行","need_bank_branch":false,"account_bank":"大洼恒丰村镇银行","account_bank_code":4874,"bank_alias_code":"1000005405"},{"bank_alias":"盘山安泰村镇银行","need_bank_branch":false,"account_bank":"盘山安泰村镇银行","account_bank_code":4875,"bank_alias_code":"1000005468"},{"bank_alias":"沂源博商村镇银行","need_bank_branch":false,"account_bank":"沂源博商村镇银行","account_bank_code":4876,"bank_alias_code":"1000005949"},{"bank_alias":"桂林国民村镇银行","need_bank_branch":false,"account_bank":"桂林国民村镇银行","account_bank_code":4877,"bank_alias_code":"1000006022"},{"bank_alias":"元氏信融村镇银行","need_bank_branch":false,"account_bank":"元氏信融村镇银行","account_bank_code":4878,"bank_alias_code":"1000006423"},{"bank_alias":"山东历城圆融村镇银行","need_bank_branch":false,"account_bank":"历城圆融村镇银行","account_bank_code":4879,"bank_alias_code":"1000005682"},{"bank_alias":"南宁江南国民村镇银行","need_bank_branch":false,"account_bank":"南宁江南国民村镇银行","account_bank_code":4880,"bank_alias_code":"1000005408"},{"bank_alias":"平坝鼎立村镇银行","need_bank_branch":false,"account_bank":"平坝鼎立村镇银行","account_bank_code":4881,"bank_alias_code":"1000005552"},{"bank_alias":"上海闵行上银村镇银行","need_bank_branch":false,"account_bank":"闵行上银村镇银行","account_bank_code":4882,"bank_alias_code":"1000005783"},{"bank_alias":"内江兴隆村镇银行","need_bank_branch":false,"account_bank":"内江兴隆村镇银行","account_bank_code":4883,"bank_alias_code":"1000006398"},{"bank_alias":"庆阳市西峰瑞信村镇银行","need_bank_branch":false,"account_bank":"瑞信村镇银行","account_bank_code":4884,"bank_alias_code":"1000005550"},{"bank_alias":"东方惠丰村镇银行","need_bank_branch":false,"account_bank":"东方惠丰村镇银行","account_bank_code":4885,"bank_alias_code":"1000005687"},{"bank_alias":"东方汇理银行","need_bank_branch":false,"account_bank":"东方汇理银行","account_bank_code":4912,"bank_alias_code":"1000009625"},{"bank_alias":"贵阳农村商业银行","need_bank_branch":false,"account_bank":"贵阳农商银行","account_bank_code":4917,"bank_alias_code":"1000007174"},{"bank_alias":"德州陵城圆融村镇银行","need_bank_branch":false,"account_bank":"陵城圆融村镇银行","account_bank_code":5712,"bank_alias_code":"1000006506"},{"bank_alias":"费县梁邹村镇银行","need_bank_branch":false,"account_bank":"费县梁邹村镇银行","account_bank_code":5713,"bank_alias_code":"1000005665"},{"bank_alias":"牟平胶东村镇银行","need_bank_branch":false,"account_bank":"牟平胶东村镇银行","account_bank_code":5714,"bank_alias_code":"1000006793"},{"bank_alias":"武安村镇银行","need_bank_branch":false,"account_bank":"武安村镇银行","account_bank_code":5716,"bank_alias_code":"1000005486"},{"bank_alias":"呼和浩特市玉泉蒙银村镇银行","need_bank_branch":false,"account_bank":"玉泉蒙银村镇银行","account_bank_code":5717,"bank_alias_code":"1000006599"},{"bank_alias":"任丘村镇银行","need_bank_branch":false,"account_bank":"任丘村镇银行","account_bank_code":5718,"bank_alias_code":"1000005658"},{"bank_alias":"遵义新蒲长征村镇银行","need_bank_branch":false,"account_bank":"遵义新蒲长征村镇银行","account_bank_code":5722,"bank_alias_code":"1000006829"},{"bank_alias":"六盘水钟山凉都村镇银行","need_bank_branch":false,"account_bank":"钟山凉都村镇银行","account_bank_code":5723,"bank_alias_code":"1000006060"},{"bank_alias":"保德县慧融村镇银行","need_bank_branch":false,"account_bank":"保德慧融村镇银行","account_bank_code":5724,"bank_alias_code":"1000006856"},{"bank_alias":"廊坊市广阳舜丰村镇银行","need_bank_branch":false,"account_bank":"广阳舜丰村镇银行","account_bank_code":5726,"bank_alias_code":"1000005398"},{"bank_alias":"大城舜丰村镇银行","need_bank_branch":false,"account_bank":"大城舜丰村镇银行","account_bank_code":5728,"bank_alias_code":"1000006583"},{"bank_alias":"山东沾化青云村镇银行","need_bank_branch":false,"account_bank":"沾化青云村镇银行","account_bank_code":5729,"bank_alias_code":"1000005350"},{"bank_alias":"夏津胶东村镇银行","need_bank_branch":false,"account_bank":"夏津胶东村镇银行","account_bank_code":5730,"bank_alias_code":"1000006463"},{"bank_alias":"山东兰陵村镇银行","need_bank_branch":false,"account_bank":"山东兰陵村镇银行","account_bank_code":5731,"bank_alias_code":"1000005662"},{"bank_alias":"安顺西航南马村镇银行","need_bank_branch":false,"account_bank":"安顺西航南马村镇银行","account_bank_code":5732,"bank_alias_code":"1000006567"},{"bank_alias":"调兵山惠民村镇银行","need_bank_branch":false,"account_bank":"调兵山惠民村镇银行","account_bank_code":5733,"bank_alias_code":"1000006737"},{"bank_alias":"宁津胶东村镇银行","need_bank_branch":false,"account_bank":"宁津胶东村镇银行","account_bank_code":5734,"bank_alias_code":"1000005892"},{"bank_alias":"浙江浦江嘉银村镇银行","need_bank_branch":false,"account_bank":"浦江嘉银村镇银行","account_bank_code":5735,"bank_alias_code":"1000006083"},{"bank_alias":"德江长征村镇银行","need_bank_branch":false,"account_bank":"德江长征村镇银行","account_bank_code":5737,"bank_alias_code":"1000005704"},{"bank_alias":"江口长征村镇银行","need_bank_branch":false,"account_bank":"江口长征村镇银行","account_bank_code":5738,"bank_alias_code":"1000006361"},{"bank_alias":"石阡长征村镇银行","need_bank_branch":false,"account_bank":"石阡长征村镇银行","account_bank_code":5739,"bank_alias_code":"1000006368"},{"bank_alias":"松桃长征村镇银行","need_bank_branch":false,"account_bank":"松桃长征村镇银行","account_bank_code":5740,"bank_alias_code":"1000005419"},{"bank_alias":"铜仁万山长征村镇银行","need_bank_branch":false,"account_bank":"铜仁万山长征村镇银行","account_bank_code":5741,"bank_alias_code":"1000006791"},{"bank_alias":"江苏江都吉银村镇银行","need_bank_branch":false,"account_bank":"江苏江都吉银村镇银行","account_bank_code":5744,"bank_alias_code":"1000005599"},{"bank_alias":"正蓝旗汇泽村镇银行","need_bank_branch":false,"account_bank":"正蓝旗汇泽村镇银行","account_bank_code":5745,"bank_alias_code":"1000006621"},{"bank_alias":"永清吉银村镇银行","need_bank_branch":false,"account_bank":"永清吉银村镇银行","account_bank_code":5746,"bank_alias_code":"1000005794"},{"bank_alias":"东丰吉银村镇银行","need_bank_branch":false,"account_bank":"东丰吉银村镇银行","account_bank_code":5747,"bank_alias_code":"1000006259"},{"bank_alias":"双辽吉银村镇银行","need_bank_branch":false,"account_bank":"双辽吉银村镇银行","account_bank_code":5748,"bank_alias_code":"1000006386"},{"bank_alias":"长春双阳吉银村镇银行","need_bank_branch":false,"account_bank":"长春双阳吉银村镇银行","account_bank_code":5749,"bank_alias_code":"1000006411"},{"bank_alias":"威海富民村镇银行","need_bank_branch":false,"account_bank":"威海富民村镇银行","account_bank_code":5750,"bank_alias_code":"1000006711"},{"bank_alias":"乐东惠丰村镇银行","need_bank_branch":false,"account_bank":"乐东惠丰村镇银行","account_bank_code":5751,"bank_alias_code":"1000005958"},{"bank_alias":"临高惠丰村镇银行","need_bank_branch":false,"account_bank":"临高惠丰村镇银行","account_bank_code":5752,"bank_alias_code":"1000006663"},{"bank_alias":"右玉县长青村镇银行","need_bank_branch":false,"account_bank":"右玉县长青村镇银行","account_bank_code":5753,"bank_alias_code":"1000005919"},{"bank_alias":"山东高青汇金村镇银行","need_bank_branch":false,"account_bank":"山东高青汇金村镇银行","account_bank_code":5755,"bank_alias_code":"1000006817"},{"bank_alias":"灵丘县长青村镇银行","need_bank_branch":false,"account_bank":"灵丘县长青村镇银行","account_bank_code":5756,"bank_alias_code":"1000005886"},{"bank_alias":"左云县长青村镇银行","need_bank_branch":false,"account_bank":"左云县长青村镇银行","account_bank_code":5757,"bank_alias_code":"1000005667"},{"bank_alias":"唐县汇泽村镇银行","need_bank_branch":false,"account_bank":"唐县汇泽村镇银行","account_bank_code":5758,"bank_alias_code":"1000006205"},{"bank_alias":"霸州舜丰村镇银行","need_bank_branch":false,"account_bank":"霸州舜丰村镇银行","account_bank_code":5759,"bank_alias_code":"1000006733"},{"bank_alias":"贵阳白云德信村镇银行","need_bank_branch":false,"account_bank":"贵阳白云德信村镇银行","account_bank_code":5760,"bank_alias_code":"1000005330"},{"bank_alias":"宝丰豫丰村镇银行","need_bank_branch":false,"account_bank":"宝丰豫丰村镇银行","account_bank_code":5761,"bank_alias_code":"1000005726"},{"bank_alias":"昌乐乐安村镇银行","need_bank_branch":false,"account_bank":"昌乐乐安村镇银行","account_bank_code":5762,"bank_alias_code":"1000006634"},{"bank_alias":"唐山市丰南舜丰村镇银行","need_bank_branch":false,"account_bank":"唐山市丰南舜丰村镇银行","account_bank_code":5763,"bank_alias_code":"1000006482"},{"bank_alias":"遵义汇川黔兴村镇银行","need_bank_branch":false,"account_bank":"遵义汇川黔兴村镇银行","account_bank_code":5766,"bank_alias_code":"1000005942"},{"bank_alias":"山东惠民舜丰村镇银行","need_bank_branch":false,"account_bank":"山东惠民舜丰村镇银行","account_bank_code":5767,"bank_alias_code":"1000006477"},{"bank_alias":"鄂尔多斯市康巴什村镇银行","need_bank_branch":false,"account_bank":"鄂尔多斯市康巴什村镇银行","account_bank_code":5768,"bank_alias_code":"1000005753"},{"bank_alias":"莱阳胶东村镇银行","need_bank_branch":false,"account_bank":"莱阳胶东村镇银行","account_bank_code":5769,"bank_alias_code":"1000005709"},{"bank_alias":"山东利津舜丰村镇银行","need_bank_branch":false,"account_bank":"山东利津舜丰村镇银行","account_bank_code":5772,"bank_alias_code":"1000006710"},{"bank_alias":"山东临淄汇金村镇银行","need_bank_branch":false,"account_bank":"山东临淄汇金村镇银行","account_bank_code":5773,"bank_alias_code":"1000006208"},{"bank_alias":"娄烦县三禾村镇银行","need_bank_branch":false,"account_bank":"娄烦县三禾村镇银行","account_bank_code":5774,"bank_alias_code":"1000005779"},{"bank_alias":"南江农科村镇银行","need_bank_branch":false,"account_bank":"南江农科村镇银行","account_bank_code":5776,"bank_alias_code":"1000006414"},{"bank_alias":"黔西花都村镇银行","need_bank_branch":false,"account_bank":"黔西花都村镇银行","account_bank_code":5779,"bank_alias_code":"1000006344"},{"bank_alias":"庆云乐安村镇银行","need_bank_branch":false,"account_bank":"庆云乐安村镇银行","account_bank_code":5781,"bank_alias_code":"1000006150"},{"bank_alias":"仁怀蒙银村镇银行","need_bank_branch":false,"account_bank":"仁怀蒙银村镇银行","account_bank_code":5782,"bank_alias_code":"1000006722"},{"bank_alias":"水城蒙银村镇银行","need_bank_branch":false,"account_bank":"水城蒙银村镇银行","account_bank_code":5783,"bank_alias_code":"1000005644"},{"bank_alias":"浙江松阳恒通村镇银行","need_bank_branch":false,"account_bank":"浙江松阳恒通村镇银行","account_bank_code":5784,"bank_alias_code":"1000006609"},{"bank_alias":"屯留县三禾村镇银行","need_bank_branch":false,"account_bank":"屯留县三禾村镇银行","account_bank_code":5786,"bank_alias_code":"1000006890"},{"bank_alias":"安徽新安银行","need_bank_branch":false,"account_bank":"安徽新安银行","account_bank_code":5789,"bank_alias_code":"1000009505"},{"bank_alias":"荥阳利丰村镇银行","need_bank_branch":false,"account_bank":"利丰村镇银行","account_bank_code":5791,"bank_alias_code":"1000005767"},{"bank_alias":"洛阳银行","need_bank_branch":false,"account_bank":"洛阳银行","account_bank_code":5794,"bank_alias_code":"1000005217"},{"bank_alias":"摩根大通银行","need_bank_branch":false,"account_bank":"摩根大通银行","account_bank_code":5840,"bank_alias_code":"1000009593"}] \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodePersonal.json b/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodePersonal.json new file mode 100644 index 0000000..3b6c3f2 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/resources/channel/sftpay/bankCodePersonal.json @@ -0,0 +1 @@ +[{"bank_alias":"招商银行","need_bank_branch":false,"account_bank":"招商银行","account_bank_code":1001,"bank_alias_code":"1000009561"},{"bank_alias":"工商银行","need_bank_branch":false,"account_bank":"工商银行","account_bank_code":1002,"bank_alias_code":"1000009547"},{"bank_alias":"建设银行","need_bank_branch":false,"account_bank":"建设银行","account_bank_code":1003,"bank_alias_code":"1000009550"},{"bank_alias":"浦发银行","need_bank_branch":false,"account_bank":"浦发银行","account_bank_code":1004,"bank_alias_code":"1000009563"},{"bank_alias":"农业银行","need_bank_branch":false,"account_bank":"农业银行","account_bank_code":1005,"bank_alias_code":"1000009548"},{"bank_alias":"民生银行","need_bank_branch":false,"account_bank":"民生银行","account_bank_code":1006,"bank_alias_code":"1000009558"},{"bank_alias":"兴业银行","need_bank_branch":false,"account_bank":"兴业银行","account_bank_code":1009,"bank_alias_code":"1000009562"},{"bank_alias":"平安银行","need_bank_branch":false,"account_bank":"平安银行","account_bank_code":1010,"bank_alias_code":"1000009560"},{"bank_alias":"交通银行","need_bank_branch":false,"account_bank":"交通银行","account_bank_code":1020,"bank_alias_code":"1000009554"},{"bank_alias":"中信银行","need_bank_branch":false,"account_bank":"中信银行","account_bank_code":1021,"bank_alias_code":"1000009555"},{"bank_alias":"光大银行","need_bank_branch":false,"account_bank":"光大银行","account_bank_code":1022,"bank_alias_code":"1000009556"},{"bank_alias":"上海银行","need_bank_branch":false,"account_bank":"上海银行","account_bank_code":1024,"bank_alias_code":"1000009569"},{"bank_alias":"华夏银行","need_bank_branch":false,"account_bank":"华夏银行","account_bank_code":1025,"bank_alias_code":"1000009557"},{"bank_alias":"中国银行","need_bank_branch":false,"account_bank":"中国银行","account_bank_code":1026,"bank_alias_code":"1000009549"},{"bank_alias":"广发银行","need_bank_branch":false,"account_bank":"广发银行","account_bank_code":1027,"bank_alias_code":"1000009559"},{"bank_alias":"南京银行","need_bank_branch":false,"account_bank":"南京银行","account_bank_code":1054,"bank_alias_code":"1000005234"},{"bank_alias":"宁波银行","need_bank_branch":false,"account_bank":"宁波银行","account_bank_code":1056,"bank_alias_code":"1000005229"},{"bank_alias":"邮政储蓄银行","need_bank_branch":false,"account_bank":"邮政储蓄银行","account_bank_code":1066,"bank_alias_code":"1000009571"},{"bank_alias":"莱商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000000001"},{"bank_alias":"廊坊银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005186"},{"bank_alias":"泰安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005187"},{"bank_alias":"凉山州商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005188"},{"bank_alias":"营口沿海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005189"},{"bank_alias":"昆仑银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005190"},{"bank_alias":"云南红塔银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005191"},{"bank_alias":"邢台银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005192"},{"bank_alias":"贵州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005193"},{"bank_alias":"江苏长江商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005195"},{"bank_alias":"广西北部湾银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005196"},{"bank_alias":"乐山市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005198"},{"bank_alias":"邯郸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005199"},{"bank_alias":"广东南粤银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005200"},{"bank_alias":"威海市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005201"},{"bank_alias":"宁波通商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005203"},{"bank_alias":"齐鲁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005204"},{"bank_alias":"甘肃银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005205"},{"bank_alias":"本溪银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005206"},{"bank_alias":"沧州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005207"},{"bank_alias":"柳州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005208"},{"bank_alias":"厦门银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005209"},{"bank_alias":"华融湘江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005210"},{"bank_alias":"辽阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005211"},{"bank_alias":"林州中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005212"},{"bank_alias":"天津银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005213"},{"bank_alias":"福建海峡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005214"},{"bank_alias":"晋中银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005216"},{"bank_alias":"遂宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005218"},{"bank_alias":"鞍山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005219"},{"bank_alias":"遵义市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005220"},{"bank_alias":"阜新银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005221"},{"bank_alias":"绍兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005222"},{"bank_alias":"临商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005224"},{"bank_alias":"龙江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005225"},{"bank_alias":"贵阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005226"},{"bank_alias":"阳泉市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005227"},{"bank_alias":"吉林银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005228"},{"bank_alias":"九江银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005230"},{"bank_alias":"嘉兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005231"},{"bank_alias":"泸州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005232"},{"bank_alias":"苏州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005233"},{"bank_alias":"铁岭银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005235"},{"bank_alias":"自贡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005236"},{"bank_alias":"济宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005237"},{"bank_alias":"上饶银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005238"},{"bank_alias":"唐山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005240"},{"bank_alias":"西安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005241"},{"bank_alias":"营口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005242"},{"bank_alias":"乌鲁木齐银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005243"},{"bank_alias":"雅安市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005244"},{"bank_alias":"宜宾市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005245"},{"bank_alias":"富滇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005247"},{"bank_alias":"张家口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005248"},{"bank_alias":"东营银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005249"},{"bank_alias":"盛京银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005250"},{"bank_alias":"河北银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005251"},{"bank_alias":"广东华兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005252"},{"bank_alias":"海南银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005254"},{"bank_alias":"哈尔滨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005255"},{"bank_alias":"赣州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005256"},{"bank_alias":"达州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005257"},{"bank_alias":"青海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005258"},{"bank_alias":"曲靖市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005259"},{"bank_alias":"成都银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005260"},{"bank_alias":"长安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005261"},{"bank_alias":"盘锦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005262"},{"bank_alias":"日照银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005263"},{"bank_alias":"攀枝花市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005264"},{"bank_alias":"承德银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005265"},{"bank_alias":"烟台银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005266"},{"bank_alias":"绵阳市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005267"},{"bank_alias":"朝阳银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005268"},{"bank_alias":"台州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005269"},{"bank_alias":"广州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005270"},{"bank_alias":"桂林银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005271"},{"bank_alias":"金华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005273"},{"bank_alias":"郑州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005274"},{"bank_alias":"丹东银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005275"},{"bank_alias":"晋城银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005276"},{"bank_alias":"蒙商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005277"},{"bank_alias":"鄂尔多斯银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005278"},{"bank_alias":"潍坊银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005279"},{"bank_alias":"焦作中旅银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005280"},{"bank_alias":"汉口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005281"},{"bank_alias":"桂林市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005282"},{"bank_alias":"浙江民泰商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005283"},{"bank_alias":"浙江稠州商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005284"},{"bank_alias":"西藏银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005286"},{"bank_alias":"兰州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005287"},{"bank_alias":"江西银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005288"},{"bank_alias":"乌海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005289"},{"bank_alias":"保定银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005290"},{"bank_alias":"珠海华润银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005291"},{"bank_alias":"四川天府银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005294"},{"bank_alias":"泸州市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005295"},{"bank_alias":"达州市商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005296"},{"bank_alias":"青岛银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005297"},{"bank_alias":"内蒙古银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005298"},{"bank_alias":"葫芦岛银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005299"},{"bank_alias":"泉州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005303"},{"bank_alias":"大连银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005304"},{"bank_alias":"新疆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005305"},{"bank_alias":"宁波东海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005308"},{"bank_alias":"石嘴山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005309"},{"bank_alias":"抚顺银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005311"},{"bank_alias":"重庆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005312"},{"bank_alias":"温州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005313"},{"bank_alias":"齐商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005314"},{"bank_alias":"平顶山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005315"},{"bank_alias":"东莞银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005316"},{"bank_alias":"锦州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005317"},{"bank_alias":"新疆汇和银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005318"},{"bank_alias":"宁夏银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005319"},{"bank_alias":"湖南岳阳湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005320"},{"bank_alias":"尚志惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005321"},{"bank_alias":"天津市蓟州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005322"},{"bank_alias":"锦州松山农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005323"},{"bank_alias":"郑州金水厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005324"},{"bank_alias":"云南西山渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005325"},{"bank_alias":"新疆石河子交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005326"},{"bank_alias":"永城齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005327"},{"bank_alias":"文山马关长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005329"},{"bank_alias":"九江共青村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005331"},{"bank_alias":"峨眉山中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005332"},{"bank_alias":"沈阳于洪永安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005333"},{"bank_alias":"双城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005334"},{"bank_alias":"重庆璧山工银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005335"},{"bank_alias":"安徽怀宁江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005336"},{"bank_alias":"福泉富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005337"},{"bank_alias":"浙江平阳浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005338"},{"bank_alias":"湖南新邵湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005339"},{"bank_alias":"资兴浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005340"},{"bank_alias":"浙江淳安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005341"},{"bank_alias":"铁岭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005342"},{"bank_alias":"四平铁东德丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005343"},{"bank_alias":"滦南中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005345"},{"bank_alias":"四川大竹渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005346"},{"bank_alias":"张家口宣化家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005347"},{"bank_alias":"苏州常熟中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005348"},{"bank_alias":"哈尔滨阿城农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005349"},{"bank_alias":"茂名高州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005351"},{"bank_alias":"湖南道县神农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005352"},{"bank_alias":"浙江富阳恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005353"},{"bank_alias":"安徽涡阳湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005354"},{"bank_alias":"保康楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005355"},{"bank_alias":"曲周恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005356"},{"bank_alias":"贵阳小河科技村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005357"},{"bank_alias":"延寿融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005358"},{"bank_alias":"惠安中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005359"},{"bank_alias":"广水楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005361"},{"bank_alias":"和顺县贵都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005362"},{"bank_alias":"望江新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005363"},{"bank_alias":"山东莒南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005364"},{"bank_alias":"昆明盘龙兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005365"},{"bank_alias":"四平铁西敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005366"},{"bank_alias":"含山惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005367"},{"bank_alias":"巨鹿融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005368"},{"bank_alias":"云南大理渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005369"},{"bank_alias":"鄢陵郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005370"},{"bank_alias":"天津宁河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005371"},{"bank_alias":"个旧沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005372"},{"bank_alias":"界首中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005373"},{"bank_alias":"四子王蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005374"},{"bank_alias":"湖南华容星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005375"},{"bank_alias":"浙江天台民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005376"},{"bank_alias":"天津华明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005377"},{"bank_alias":"土默特右旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005378"},{"bank_alias":"竹山楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005379"},{"bank_alias":"陕西商南聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005380"},{"bank_alias":"固安恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005381"},{"bank_alias":"安徽凤台通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005382"},{"bank_alias":"云南香格里拉渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005383"},{"bank_alias":"围场满族蒙古族自治县华商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005384"},{"bank_alias":"旌德民商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005385"},{"bank_alias":"滑县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005386"},{"bank_alias":"江苏海门中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005387"},{"bank_alias":"任县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005388"},{"bank_alias":"贵阳云岩富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005389"},{"bank_alias":"成都双流诚民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005390"},{"bank_alias":"淮安淮阴兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005391"},{"bank_alias":"庆城县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005392"},{"bank_alias":"睢县德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005393"},{"bank_alias":"兰州安宁神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005394"},{"bank_alias":"宁夏西吉汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005395"},{"bank_alias":"大厂回族自治县新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005396"},{"bank_alias":"四川北川羌族富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005397"},{"bank_alias":"福建石狮渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005399"},{"bank_alias":"涉县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005400"},{"bank_alias":"安徽青阳九华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005401"},{"bank_alias":"辽宁北镇锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005402"},{"bank_alias":"东宁润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005403"},{"bank_alias":"南康赣商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005404"},{"bank_alias":"深圳福田银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005406"},{"bank_alias":"西藏堆龙民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005407"},{"bank_alias":"晴隆兴安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005409"},{"bank_alias":"禹州新民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005410"},{"bank_alias":"依安润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005411"},{"bank_alias":"南宁武鸣漓江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005412"},{"bank_alias":"讷河融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005413"},{"bank_alias":"广西鹿寨渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005414"},{"bank_alias":"京山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005415"},{"bank_alias":"重庆彭水民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005416"},{"bank_alias":"依兰惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005417"},{"bank_alias":"江苏灌云民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005418"},{"bank_alias":"开远沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005420"},{"bank_alias":"宁夏盐池汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005421"},{"bank_alias":"包头市高新银通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005423"},{"bank_alias":"鹤山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005424"},{"bank_alias":"藁城恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005425"},{"bank_alias":"乐平融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005427"},{"bank_alias":"乌鲁木齐米东浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005429"},{"bank_alias":"进贤瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005430"},{"bank_alias":"陕西汉中南郑汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005431"},{"bank_alias":"南宁隆安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005432"},{"bank_alias":"深泽利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005433"},{"bank_alias":"安阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005434"},{"bank_alias":"喀喇沁玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005435"},{"bank_alias":"长春净月榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005436"},{"bank_alias":"湖南浏阳江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005437"},{"bank_alias":"神农架楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005438"},{"bank_alias":"云霄润发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005439"},{"bank_alias":"辽宁灯塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005440"},{"bank_alias":"巫山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005441"},{"bank_alias":"辽宁太子河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005442"},{"bank_alias":"铜川耀州新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005443"},{"bank_alias":"赤峰市元宝山玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005444"},{"bank_alias":"无为徽银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005445"},{"bank_alias":"福建沙县渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005446"},{"bank_alias":"襄城汇浦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005447"},{"bank_alias":"蛟河吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005448"},{"bank_alias":"兰考齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005449"},{"bank_alias":"西安高陵阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005450"},{"bank_alias":"江苏丰县民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005451"},{"bank_alias":"济宁高新村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005452"},{"bank_alias":"青岛莱西元泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005453"},{"bank_alias":"重庆长寿中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005454"},{"bank_alias":"平舆玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005455"},{"bank_alias":"天长民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005456"},{"bank_alias":"正定恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005457"},{"bank_alias":"綦江民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005459"},{"bank_alias":"广东恩平汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005460"},{"bank_alias":"重庆市沙坪坝融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005461"},{"bank_alias":"伊川齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005462"},{"bank_alias":"古田刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005463"},{"bank_alias":"深圳龙岗鼎业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005464"},{"bank_alias":"平和润丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005465"},{"bank_alias":"秦皇岛抚宁家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005466"},{"bank_alias":"湖南邵阳湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005467"},{"bank_alias":"浙江武义中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005469"},{"bank_alias":"天津滨海江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005470"},{"bank_alias":"阳江阳春长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005471"},{"bank_alias":"句容苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005472"},{"bank_alias":"浙江定海德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005473"},{"bank_alias":"山东莱山齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005474"},{"bank_alias":"南漳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005476"},{"bank_alias":"黄梅中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005477"},{"bank_alias":"浙江永嘉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005478"},{"bank_alias":"池州贵池民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005479"},{"bank_alias":"师宗兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005480"},{"bank_alias":"湖南冷水江湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005481"},{"bank_alias":"紫云富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005482"},{"bank_alias":"鄂尔多斯市铁西蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005483"},{"bank_alias":"呼和浩特市赛罕金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005484"},{"bank_alias":"洛宁兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005485"},{"bank_alias":"偃师融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005487"},{"bank_alias":"海南保亭融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005488"},{"bank_alias":"灵山泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005489"},{"bank_alias":"武强家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005490"},{"bank_alias":"廊坊市安次区惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005491"},{"bank_alias":"平泉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005492"},{"bank_alias":"开封新东方村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005493"},{"bank_alias":"鄂尔多斯市天骄蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005494"},{"bank_alias":"抚州东乡富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005495"},{"bank_alias":"平昌农科村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005496"},{"bank_alias":"吉安稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005497"},{"bank_alias":"老河口中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005498"},{"bank_alias":"永兴沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005499"},{"bank_alias":"河南汝南泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005500"},{"bank_alias":"福建罗源汇融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005501"},{"bank_alias":"通化融达村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005502"},{"bank_alias":"容城邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005503"},{"bank_alias":"乌海市海勃湾黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005504"},{"bank_alias":"夏县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005505"},{"bank_alias":"五原蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005508"},{"bank_alias":"济阳北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005509"},{"bank_alias":"江西上栗富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005510"},{"bank_alias":"中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005511"},{"bank_alias":"重庆铜梁浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005512"},{"bank_alias":"浙江余杭德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005513"},{"bank_alias":"遵义红花岗富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005514"},{"bank_alias":"成都郫都中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005515"},{"bank_alias":"湖南新化星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005516"},{"bank_alias":"西安长安新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005517"},{"bank_alias":"洪湖融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005518"},{"bank_alias":"河南商水厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005519"},{"bank_alias":"泰州高港兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005520"},{"bank_alias":"长春宽城融汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005521"},{"bank_alias":"宁夏原州津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005522"},{"bank_alias":"辽宁喀左锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005523"},{"bank_alias":"铜仁丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005524"},{"bank_alias":"张家口万全家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005525"},{"bank_alias":"浙江诸暨联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005527"},{"bank_alias":"贺州八步东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005528"},{"bank_alias":"磁县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005529"},{"bank_alias":"通化二道江瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005530"},{"bank_alias":"韶山光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005531"},{"bank_alias":"福建新罗晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005532"},{"bank_alias":"自贡中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005533"},{"bank_alias":"宁夏彭阳贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005534"},{"bank_alias":"江苏东海张农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005535"},{"bank_alias":"临澧沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005536"},{"bank_alias":"浙江海盐湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005537"},{"bank_alias":"丰城顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005538"},{"bank_alias":"辽宁台安金安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005539"},{"bank_alias":"邯郸永年齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005540"},{"bank_alias":"浙江仙居富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005541"},{"bank_alias":"武川立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005542"},{"bank_alias":"甘肃泾川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005543"},{"bank_alias":"山东芝罘齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005545"},{"bank_alias":"福建平潭渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005546"},{"bank_alias":"陇南市武都金桥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005547"},{"bank_alias":"正阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005548"},{"bank_alias":"乌鲁木齐县利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005549"},{"bank_alias":"醴陵沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005551"},{"bank_alias":"晋中市榆次融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005553"},{"bank_alias":"会宁会师村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005554"},{"bank_alias":"五台莱商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005555"},{"bank_alias":"吕梁孝义汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005556"},{"bank_alias":"济南槐荫沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005557"},{"bank_alias":"本溪丰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005558"},{"bank_alias":"本溪同盛村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005559"},{"bank_alias":"福建闽侯民本村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005560"},{"bank_alias":"平凉市静宁成纪村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005561"},{"bank_alias":"浙江临海湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005562"},{"bank_alias":"穆棱远东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005563"},{"bank_alias":"海南五指山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005564"},{"bank_alias":"谷城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005565"},{"bank_alias":"福建政和泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005566"},{"bank_alias":"枣阳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005567"},{"bank_alias":"武汉江夏民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005568"},{"bank_alias":"湖北咸安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005569"},{"bank_alias":"茂名电白长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005570"},{"bank_alias":"公主岭华兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005571"},{"bank_alias":"西丰鹿城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005572"},{"bank_alias":"重庆黔江银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005573"},{"bank_alias":"富民浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005574"},{"bank_alias":"南昌新建恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005575"},{"bank_alias":"当阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005576"},{"bank_alias":"抚顺市清原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005577"},{"bank_alias":"鄄城包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005578"},{"bank_alias":"重庆云阳恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005579"},{"bank_alias":"杞县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005580"},{"bank_alias":"天津滨海德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005581"},{"bank_alias":"横峰恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005582"},{"bank_alias":"贵安新区发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005583"},{"bank_alias":"江苏江宁上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005584"},{"bank_alias":"昌图民祥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005585"},{"bank_alias":"安徽黟县新淮河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005586"},{"bank_alias":"瓦房店长兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005587"},{"bank_alias":"厦门同安农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005588"},{"bank_alias":"什邡市思源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005589"},{"bank_alias":"察哈尔右翼前旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005591"},{"bank_alias":"沈阳新民富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005592"},{"bank_alias":"武陟射阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005593"},{"bank_alias":"临沧临翔沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005594"},{"bank_alias":"贵定恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005595"},{"bank_alias":"茌平沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005596"},{"bank_alias":"浙江长兴联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005597"},{"bank_alias":"江苏大丰江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005598"},{"bank_alias":"河南西华厦农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005600"},{"bank_alias":"易门兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005601"},{"bank_alias":"台前德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005602"},{"bank_alias":"蓬溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005603"},{"bank_alias":"安龙兴龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005604"},{"bank_alias":"浙江海宁德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005605"},{"bank_alias":"重庆北碚稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005606"},{"bank_alias":"安徽肥西石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005607"},{"bank_alias":"湖南芷江湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005608"},{"bank_alias":"厦门翔安民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005609"},{"bank_alias":"大连经济技术开发区鑫汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005610"},{"bank_alias":"乌苏利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005612"},{"bank_alias":"平遥县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005613"},{"bank_alias":"天津宝坻浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005614"},{"bank_alias":"呼图壁津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005615"},{"bank_alias":"繁峙县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005616"},{"bank_alias":"临清沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005617"},{"bank_alias":"汨罗中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005618"},{"bank_alias":"大安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005619"},{"bank_alias":"上海嘉定洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005620"},{"bank_alias":"湖南汝城新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005621"},{"bank_alias":"深圳宝安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005622"},{"bank_alias":"纳雍富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005623"},{"bank_alias":"浙江青田中银富登华侨村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005624"},{"bank_alias":"汶上中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005625"},{"bank_alias":"白山江源汇恒村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005626"},{"bank_alias":"安徽长丰科源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005627"},{"bank_alias":"阳信河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005628"},{"bank_alias":"平定县昌都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005630"},{"bank_alias":"三都富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005631"},{"bank_alias":"册亨富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005632"},{"bank_alias":"江苏丹徒蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005633"},{"bank_alias":"广州花都稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005634"},{"bank_alias":"盂县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005635"},{"bank_alias":"溧阳浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005636"},{"bank_alias":"安丘北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005637"},{"bank_alias":"五莲中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005638"},{"bank_alias":"湖南新宁潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005639"},{"bank_alias":"图们敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005641"},{"bank_alias":"青岛城阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005642"},{"bank_alias":"始兴大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005643"},{"bank_alias":"赤水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005645"},{"bank_alias":"浙江平湖工银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005646"},{"bank_alias":"广西鱼峰信合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005647"},{"bank_alias":"安徽霍邱联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005648"},{"bank_alias":"江苏灌南民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005649"},{"bank_alias":"凯里东南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005650"},{"bank_alias":"湖北麻城汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005651"},{"bank_alias":"云南安宁稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005652"},{"bank_alias":"广西桂平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005653"},{"bank_alias":"保山龙陵长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005654"},{"bank_alias":"浙江舟山普陀稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005655"},{"bank_alias":"高碑店中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005656"},{"bank_alias":"仙桃楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005657"},{"bank_alias":"江苏金湖民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005659"},{"bank_alias":"鄂托克前旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005660"},{"bank_alias":"云南祥云渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005661"},{"bank_alias":"彭州民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005663"},{"bank_alias":"萍乡安源富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005664"},{"bank_alias":"曲阳中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005666"},{"bank_alias":"淮安清河兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005668"},{"bank_alias":"太原市尖草坪区信都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005669"},{"bank_alias":"秭归兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005670"},{"bank_alias":"阜新农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005671"},{"bank_alias":"南充嘉陵中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005672"},{"bank_alias":"四川成都龙泉驿稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005673"},{"bank_alias":"乐山嘉州民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005674"},{"bank_alias":"江苏泗洪东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005675"},{"bank_alias":"敖汉惠农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005676"},{"bank_alias":"北京通州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005678"},{"bank_alias":"江苏锡山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005679"},{"bank_alias":"江西上高富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005680"},{"bank_alias":"桂阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005681"},{"bank_alias":"湖南南县湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005683"},{"bank_alias":"监利中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005684"},{"bank_alias":"余姚通济村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005685"},{"bank_alias":"江西兴国新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005686"},{"bank_alias":"光泽刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005688"},{"bank_alias":"云南马龙北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005689"},{"bank_alias":"威宁富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005690"},{"bank_alias":"镇宁汇商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005691"},{"bank_alias":"泰和中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005692"},{"bank_alias":"上海奉贤浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005694"},{"bank_alias":"祁县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005695"},{"bank_alias":"青龙融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005696"},{"bank_alias":"丹寨富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005697"},{"bank_alias":"林芝民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005698"},{"bank_alias":"江苏宿豫东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005699"},{"bank_alias":"枣强丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005700"},{"bank_alias":"兴仁振兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005701"},{"bank_alias":"敦煌市金盛村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005702"},{"bank_alias":"浙江三门银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005705"},{"bank_alias":"新干中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005706"},{"bank_alias":"潼南民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005707"},{"bank_alias":"交城县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005708"},{"bank_alias":"泸县元通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005711"},{"bank_alias":"文水县润都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005712"},{"bank_alias":"金溪抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005713"},{"bank_alias":"郑州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005714"},{"bank_alias":"资阳民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005715"},{"bank_alias":"新津珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005716"},{"bank_alias":"湘乡市村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005717"},{"bank_alias":"山东平邑汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005718"},{"bank_alias":"庄河汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005719"},{"bank_alias":"湖南邵东湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005720"},{"bank_alias":"南皮融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005721"},{"bank_alias":"长春二道农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005722"},{"bank_alias":"同江汇鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005723"},{"bank_alias":"枞阳泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005725"},{"bank_alias":"霞浦刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005727"},{"bank_alias":"福建永安汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005728"},{"bank_alias":"沿河长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005729"},{"bank_alias":"抚顺东洲抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005730"},{"bank_alias":"湖南津市湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005731"},{"bank_alias":"新安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005732"},{"bank_alias":"崇州上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005733"},{"bank_alias":"定安合丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005734"},{"bank_alias":"武定兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005735"},{"bank_alias":"大连普兰店汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005736"},{"bank_alias":"上海崇明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005737"},{"bank_alias":"浙江瑞安湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005738"},{"bank_alias":"庐山九银艺术村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005739"},{"bank_alias":"嘉祥中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005740"},{"bank_alias":"湖南洪江湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005741"},{"bank_alias":"昆明官渡沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005742"},{"bank_alias":"乌拉特前旗大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005743"},{"bank_alias":"宾阳北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005744"},{"bank_alias":"云南鹤庆渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005745"},{"bank_alias":"石柱中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005746"},{"bank_alias":"广西藤县桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005747"},{"bank_alias":"梅河口民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005748"},{"bank_alias":"沈丘中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005749"},{"bank_alias":"福建泉州台商投资区晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005750"},{"bank_alias":"湖北汉川农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005751"},{"bank_alias":"福建仙游瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005752"},{"bank_alias":"东莞大朗东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005754"},{"bank_alias":"沈阳沈北富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005756"},{"bank_alias":"新郑郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005757"},{"bank_alias":"南靖中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005758"},{"bank_alias":"安徽裕安盛平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005759"},{"bank_alias":"四川名山锦程村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005760"},{"bank_alias":"广西北流柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005761"},{"bank_alias":"呼和浩特市赛罕蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005763"},{"bank_alias":"大悟楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005764"},{"bank_alias":"望都中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005765"},{"bank_alias":"大方富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005766"},{"bank_alias":"重庆城口中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005768"},{"bank_alias":"瓮安富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005770"},{"bank_alias":"海林远东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005771"},{"bank_alias":"淄博淄川北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005772"},{"bank_alias":"巩义浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005773"},{"bank_alias":"桦南融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005774"},{"bank_alias":"宽城融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005775"},{"bank_alias":"武穴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005776"},{"bank_alias":"衡阳县沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005777"},{"bank_alias":"江苏泰兴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005778"},{"bank_alias":"山阴县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005780"},{"bank_alias":"铁岭新星村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005781"},{"bank_alias":"安新大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005782"},{"bank_alias":"嵩县兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005784"},{"bank_alias":"陕西榆林横山汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005785"},{"bank_alias":"阜平大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005786"},{"bank_alias":"房县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005787"},{"bank_alias":"曲阜中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005788"},{"bank_alias":"浮梁农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005789"},{"bank_alias":"宁乡沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005790"},{"bank_alias":"江门开平长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005791"},{"bank_alias":"枝江汉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005792"},{"bank_alias":"巴彦融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005793"},{"bank_alias":"阳谷沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005795"},{"bank_alias":"威县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005796"},{"bank_alias":"辽宁海城金海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005797"},{"bank_alias":"曲靖会泽长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005798"},{"bank_alias":"浙江兰溪越商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005799"},{"bank_alias":"四川仪陇惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005800"},{"bank_alias":"望谟富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005801"},{"bank_alias":"铜川印台恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005802"},{"bank_alias":"宁武县瑞都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005803"},{"bank_alias":"松原宁江惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005804"},{"bank_alias":"拜泉融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005805"},{"bank_alias":"沈阳法库富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005806"},{"bank_alias":"凉城县乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005807"},{"bank_alias":"南京六合九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005808"},{"bank_alias":"稷山县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005809"},{"bank_alias":"磐石吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005810"},{"bank_alias":"三亚惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005811"},{"bank_alias":"盘州万和村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005812"},{"bank_alias":"平阴蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005813"},{"bank_alias":"吉林丰满惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005814"},{"bank_alias":"代县泓都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005815"},{"bank_alias":"湖南桃江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005816"},{"bank_alias":"交口县融都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005817"},{"bank_alias":"安徽铜陵铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005818"},{"bank_alias":"柳河蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005819"},{"bank_alias":"哈尔滨幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005820"},{"bank_alias":"景德镇昌江九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005821"},{"bank_alias":"五常惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005822"},{"bank_alias":"平原圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005823"},{"bank_alias":"榆中浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005824"},{"bank_alias":"钟祥民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005825"},{"bank_alias":"宁夏贺兰回商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005826"},{"bank_alias":"乌海市乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005827"},{"bank_alias":"辽宁桓仁锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005828"},{"bank_alias":"开原象牙山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005829"},{"bank_alias":"安徽寿县联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005830"},{"bank_alias":"五峰金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005831"},{"bank_alias":"通辽金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005832"},{"bank_alias":"和政神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005833"},{"bank_alias":"湖南江华新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005834"},{"bank_alias":"云南元江北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005835"},{"bank_alias":"扬州广陵中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005836"},{"bank_alias":"锦州太和锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005837"},{"bank_alias":"大理宾川长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005838"},{"bank_alias":"长顺富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005839"},{"bank_alias":"广西陆川柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005840"},{"bank_alias":"安徽明光民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005841"},{"bank_alias":"安徽巢湖扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005842"},{"bank_alias":"福建德化成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005843"},{"bank_alias":"道真中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005844"},{"bank_alias":"天水市秦安众信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005845"},{"bank_alias":"桦川融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005846"},{"bank_alias":"东乌珠穆沁农信开元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005849"},{"bank_alias":"陕西咸阳渭城汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005850"},{"bank_alias":"深圳光明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005851"},{"bank_alias":"兰州永登新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005852"},{"bank_alias":"内蒙古托克托立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005853"},{"bank_alias":"洮南惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005854"},{"bank_alias":"浙江景宁银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005855"},{"bank_alias":"台江富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005856"},{"bank_alias":"武宁恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005857"},{"bank_alias":"务川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005858"},{"bank_alias":"屏南刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005859"},{"bank_alias":"兰州七里河新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005860"},{"bank_alias":"宽甸百丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005861"},{"bank_alias":"云南西山北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005862"},{"bank_alias":"通城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005863"},{"bank_alias":"惠水恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005864"},{"bank_alias":"武夷山本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005865"},{"bank_alias":"安徽休宁大地村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005866"},{"bank_alias":"湖北嘉鱼吴江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005867"},{"bank_alias":"浙江嘉善联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005868"},{"bank_alias":"广州增城长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005869"},{"bank_alias":"岚县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005870"},{"bank_alias":"烟台福山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005871"},{"bank_alias":"柘荣刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005872"},{"bank_alias":"山东沂南蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005873"},{"bank_alias":"青岛崂山交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005875"},{"bank_alias":"垣曲县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005876"},{"bank_alias":"广西横县桂商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005877"},{"bank_alias":"廊坊开发区融商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005878"},{"bank_alias":"浙江丽水莲都中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005879"},{"bank_alias":"莱芜珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005880"},{"bank_alias":"登封齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005881"},{"bank_alias":"岑溪市北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005882"},{"bank_alias":"彭山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005883"},{"bank_alias":"文山砚山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005884"},{"bank_alias":"安徽凤阳利民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005885"},{"bank_alias":"陕西陇县长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005887"},{"bank_alias":"浙江泰顺温银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005888"},{"bank_alias":"乳山天骄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005889"},{"bank_alias":"毕节发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005890"},{"bank_alias":"中山东凤珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005891"},{"bank_alias":"福建将乐成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005893"},{"bank_alias":"陕西太白长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005894"},{"bank_alias":"安溪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005895"},{"bank_alias":"浙江萧山湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005896"},{"bank_alias":"宁波江北富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005897"},{"bank_alias":"福建永春漳农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005898"},{"bank_alias":"陵水惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005899"},{"bank_alias":"民勤融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005900"},{"bank_alias":"阜康津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005901"},{"bank_alias":"白山浑江恒泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005902"},{"bank_alias":"中卫香山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005903"},{"bank_alias":"沧县吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005904"},{"bank_alias":"石嘴山市大武口石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005905"},{"bank_alias":"江苏沭阳东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005906"},{"bank_alias":"湖南衡山潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005907"},{"bank_alias":"蓬莱民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005908"},{"bank_alias":"浙江秀洲德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005909"},{"bank_alias":"温县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005910"},{"bank_alias":"中阳县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005911"},{"bank_alias":"郧西楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005912"},{"bank_alias":"无棣中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005913"},{"bank_alias":"腾冲民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005914"},{"bank_alias":"河南方城凤裕村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005915"},{"bank_alias":"呼和浩特市新城蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005916"},{"bank_alias":"福建尤溪成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005918"},{"bank_alias":"上海青浦惠金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005920"},{"bank_alias":"日照沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005921"},{"bank_alias":"上海浦东恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005922"},{"bank_alias":"重庆丰都汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005923"},{"bank_alias":"来安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005924"},{"bank_alias":"浙江常山联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005925"},{"bank_alias":"苏州吴中珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005926"},{"bank_alias":"金寨徽银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005927"},{"bank_alias":"怀仁县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005928"},{"bank_alias":"临猗县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005929"},{"bank_alias":"辽源龙山榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005930"},{"bank_alias":"武胜中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005931"},{"bank_alias":"西昌金信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005932"},{"bank_alias":"阿拉尔津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005933"},{"bank_alias":"都江堰金都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005934"},{"bank_alias":"平凉崆峒融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005935"},{"bank_alias":"抚松榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005936"},{"bank_alias":"永新庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005937"},{"bank_alias":"梅州客家村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005938"},{"bank_alias":"大理巍山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005939"},{"bank_alias":"临洮县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005940"},{"bank_alias":"临汾市尧都区惠都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005941"},{"bank_alias":"宁波慈溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005943"},{"bank_alias":"福建连江恒欣村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005944"},{"bank_alias":"东莞常平新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005945"},{"bank_alias":"广西平南桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005946"},{"bank_alias":"福建长乐泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005947"},{"bank_alias":"饶阳民商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005948"},{"bank_alias":"宜兴阳羡村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005950"},{"bank_alias":"蓝田中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005951"},{"bank_alias":"集安惠鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005952"},{"bank_alias":"项城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005953"},{"bank_alias":"大邑交银兴民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005954"},{"bank_alias":"五华惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005955"},{"bank_alias":"聊城沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005957"},{"bank_alias":"昭通昭阳富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005959"},{"bank_alias":"福建建阳瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005960"},{"bank_alias":"吉林龙潭华益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005961"},{"bank_alias":"陕西三原海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005962"},{"bank_alias":"朝阳柳城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005964"},{"bank_alias":"西双版纳勐海长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005965"},{"bank_alias":"富锦幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005966"},{"bank_alias":"德兴蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005967"},{"bank_alias":"福建福清泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005968"},{"bank_alias":"吉水庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005969"},{"bank_alias":"青岛即墨惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005970"},{"bank_alias":"萍乡湘东黄海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005971"},{"bank_alias":"大连甘井子浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005972"},{"bank_alias":"深圳龙华新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005973"},{"bank_alias":"曲靖富源富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005974"},{"bank_alias":"重庆巫溪中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005975"},{"bank_alias":"天镇县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005976"},{"bank_alias":"武城圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005977"},{"bank_alias":"沙洋中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005978"},{"bank_alias":"昆明晋宁融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005979"},{"bank_alias":"辽源西安区榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005980"},{"bank_alias":"奇台利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005981"},{"bank_alias":"北京门头沟珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005982"},{"bank_alias":"崇仁九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005983"},{"bank_alias":"安平惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005984"},{"bank_alias":"东莞虎门长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005985"},{"bank_alias":"万州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005986"},{"bank_alias":"金沙富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005987"},{"bank_alias":"百色右江华润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005988"},{"bank_alias":"邹平浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005989"},{"bank_alias":"行唐利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005990"},{"bank_alias":"广汉珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005991"},{"bank_alias":"福建蕉城刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005992"},{"bank_alias":"从江月明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005993"},{"bank_alias":"阜南中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005994"},{"bank_alias":"慈利沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005995"},{"bank_alias":"文昌大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005997"},{"bank_alias":"广西桂平桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000005998"},{"bank_alias":"北京大兴九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006001"},{"bank_alias":"青海乐都三江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006002"},{"bank_alias":"双峰沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006003"},{"bank_alias":"重庆巴南浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006004"},{"bank_alias":"日照九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006005"},{"bank_alias":"寿光张农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006006"},{"bank_alias":"辉县珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006007"},{"bank_alias":"泰州姜堰锡州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006008"},{"bank_alias":"湖北荆门掇刀包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006009"},{"bank_alias":"广东英德泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006010"},{"bank_alias":"晋中市左权华丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006011"},{"bank_alias":"思南长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006012"},{"bank_alias":"旬邑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006013"},{"bank_alias":"巴彦淖尔市临河黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006014"},{"bank_alias":"浙江义乌联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006015"},{"bank_alias":"浙江文成北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006016"},{"bank_alias":"浙江玉环永兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006017"},{"bank_alias":"富蕴中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006019"},{"bank_alias":"杭锦大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006020"},{"bank_alias":"上海松江民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006021"},{"bank_alias":"重庆涪陵中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006023"},{"bank_alias":"忻州市忻府区秀都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006024"},{"bank_alias":"巴中中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006025"},{"bank_alias":"东莞长安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006026"},{"bank_alias":"宿迁宿城兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006027"},{"bank_alias":"伊金霍洛金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006029"},{"bank_alias":"河南叶县泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006030"},{"bank_alias":"湖口九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006031"},{"bank_alias":"海阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006033"},{"bank_alias":"河间融惠村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006034"},{"bank_alias":"无锡滨湖兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006035"},{"bank_alias":"浙江新昌浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006036"},{"bank_alias":"潜江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006037"},{"bank_alias":"陕西洛南阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006038"},{"bank_alias":"湖南平江汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006039"},{"bank_alias":"湖南中方新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006040"},{"bank_alias":"合阳惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006041"},{"bank_alias":"青原庐陵村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006042"},{"bank_alias":"莒县金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006043"},{"bank_alias":"黎川抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006044"},{"bank_alias":"江苏启东珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006045"},{"bank_alias":"通许融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006046"},{"bank_alias":"成安齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006047"},{"bank_alias":"福建南安汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006048"},{"bank_alias":"韩城浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006049"},{"bank_alias":"哈尔滨宾洲村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006050"},{"bank_alias":"弋阳蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006051"},{"bank_alias":"福建泰宁晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006052"},{"bank_alias":"杜尔伯特润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006053"},{"bank_alias":"本溪禾丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006054"},{"bank_alias":"竹溪楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006055"},{"bank_alias":"孝昌本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006056"},{"bank_alias":"天津市北辰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006057"},{"bank_alias":"伊金霍洛六菱村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006058"},{"bank_alias":"云南石屏北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006059"},{"bank_alias":"铜鼓九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006061"},{"bank_alias":"宁夏同心津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006062"},{"bank_alias":"宁夏西夏贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006063"},{"bank_alias":"保定满城区利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006064"},{"bank_alias":"安徽濉溪湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006065"},{"bank_alias":"安徽肥东湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006066"},{"bank_alias":"定陶河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006067"},{"bank_alias":"建平红山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006068"},{"bank_alias":"山东郯城汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006069"},{"bank_alias":"哈密天山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006070"},{"bank_alias":"井冈山九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006071"},{"bank_alias":"重庆忠县稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006072"},{"bank_alias":"奉节中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006073"},{"bank_alias":"贵溪九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006074"},{"bank_alias":"宁海中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006075"},{"bank_alias":"松滋中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006076"},{"bank_alias":"上海宝山扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006077"},{"bank_alias":"新密郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006078"},{"bank_alias":"镇赉中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006080"},{"bank_alias":"浙江桐庐恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006081"},{"bank_alias":"滦州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006082"},{"bank_alias":"独山富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006084"},{"bank_alias":"北票盛都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006085"},{"bank_alias":"重庆南川石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006087"},{"bank_alias":"安徽桐城江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006088"},{"bank_alias":"山东成武汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006090"},{"bank_alias":"壶关县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006091"},{"bank_alias":"沈阳辽中富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006092"},{"bank_alias":"阜宁民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006093"},{"bank_alias":"上海金山惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006094"},{"bank_alias":"临武浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006095"},{"bank_alias":"临邑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006096"},{"bank_alias":"信阳平桥中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006097"},{"bank_alias":"恩施兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006098"},{"bank_alias":"鹰潭月湖恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006099"},{"bank_alias":"江苏新沂汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006100"},{"bank_alias":"雅安雨城惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006101"},{"bank_alias":"东港同合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006102"},{"bank_alias":"广西容县桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006103"},{"bank_alias":"葫芦岛国信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006104"},{"bank_alias":"灵宝融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006105"},{"bank_alias":"阜城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006106"},{"bank_alias":"罗平兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006107"},{"bank_alias":"安徽繁昌中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006108"},{"bank_alias":"宁夏红寺堡汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006109"},{"bank_alias":"宜昌夷陵兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006110"},{"bank_alias":"海伦惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006111"},{"bank_alias":"公主岭浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006112"},{"bank_alias":"沂水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006113"},{"bank_alias":"海南白沙长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006114"},{"bank_alias":"祁阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006115"},{"bank_alias":"昆明呈贡华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006116"},{"bank_alias":"山东邹城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006117"},{"bank_alias":"应城融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006118"},{"bank_alias":"东营河口中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006119"},{"bank_alias":"保定清苑区邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006120"},{"bank_alias":"克山润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006121"},{"bank_alias":"南丰桔都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006122"},{"bank_alias":"浠水楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006123"},{"bank_alias":"兴城长兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006124"},{"bank_alias":"湖北红安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006125"},{"bank_alias":"长宁中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006126"},{"bank_alias":"卓资蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006127"},{"bank_alias":"崇阳楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006128"},{"bank_alias":"潍坊市寒亭区蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006129"},{"bank_alias":"三河蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006130"},{"bank_alias":"安徽徽州铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006131"},{"bank_alias":"莱芜中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006132"},{"bank_alias":"资溪九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006133"},{"bank_alias":"浙江安吉交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006135"},{"bank_alias":"安徽蒙城湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006137"},{"bank_alias":"涟源沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006138"},{"bank_alias":"邯郸邯山齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006139"},{"bank_alias":"河南栾川民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006140"},{"bank_alias":"贵阳观山湖富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006141"},{"bank_alias":"百色靖西长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006142"},{"bank_alias":"吉州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006143"},{"bank_alias":"山东梁山民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006144"},{"bank_alias":"赤峰市松山立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006145"},{"bank_alias":"广西博白柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006146"},{"bank_alias":"三水珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006147"},{"bank_alias":"合川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006148"},{"bank_alias":"辉南榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006151"},{"bank_alias":"凤翔中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006153"},{"bank_alias":"江苏泗阳东吴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006154"},{"bank_alias":"翁牛特立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006155"},{"bank_alias":"城固中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006157"},{"bank_alias":"曲靖宣威长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006158"},{"bank_alias":"安徽舒城正兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006159"},{"bank_alias":"长春高新惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006160"},{"bank_alias":"颍上中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006161"},{"bank_alias":"随县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006162"},{"bank_alias":"苍梧深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006163"},{"bank_alias":"九江恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006164"},{"bank_alias":"安图农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006165"},{"bank_alias":"杭锦后旗河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006167"},{"bank_alias":"吴忠市滨河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006168"},{"bank_alias":"黄平振兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006169"},{"bank_alias":"江苏盱眙珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006170"},{"bank_alias":"福建宁化成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006171"},{"bank_alias":"新疆建新成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006172"},{"bank_alias":"浙江苍南中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006173"},{"bank_alias":"罗甸发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006174"},{"bank_alias":"清镇兴邦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006175"},{"bank_alias":"广西融水柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006176"},{"bank_alias":"孟村回族自治县融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006177"},{"bank_alias":"郏县广天村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006178"},{"bank_alias":"遂平中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006179"},{"bank_alias":"石门沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006180"},{"bank_alias":"江苏洪泽金阳光村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006181"},{"bank_alias":"南华兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006182"},{"bank_alias":"海南琼中长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006183"},{"bank_alias":"云安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006184"},{"bank_alias":"长岭蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006185"},{"bank_alias":"广饶梁邹村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006186"},{"bank_alias":"景洪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006188"},{"bank_alias":"吴江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006189"},{"bank_alias":"樟树顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006190"},{"bank_alias":"安徽潜山江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006192"},{"bank_alias":"承德县恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006193"},{"bank_alias":"浙江上虞富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006194"},{"bank_alias":"安徽定远民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006195"},{"bank_alias":"昌邑北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006196"},{"bank_alias":"鄱阳恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006197"},{"bank_alias":"大同市南郊区京都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006198"},{"bank_alias":"大理古城中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006199"},{"bank_alias":"卢氏中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006200"},{"bank_alias":"郓城北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006201"},{"bank_alias":"丹东鼎安村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006202"},{"bank_alias":"太和中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006203"},{"bank_alias":"田东北部湾村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006204"},{"bank_alias":"浙江磐安婺商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006206"},{"bank_alias":"重庆秀山北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006207"},{"bank_alias":"志丹民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006209"},{"bank_alias":"上杭中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006210"},{"bank_alias":"安徽灵璧本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006211"},{"bank_alias":"汾西县亿通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006212"},{"bank_alias":"普安普惠村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006213"},{"bank_alias":"修水九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006214"},{"bank_alias":"佛山高明顺银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006215"},{"bank_alias":"河津市龙都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006216"},{"bank_alias":"福建永定瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006217"},{"bank_alias":"日照蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006218"},{"bank_alias":"曲沃县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006219"},{"bank_alias":"重庆荣昌汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006220"},{"bank_alias":"睢宁中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006221"},{"bank_alias":"深圳罗湖蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006222"},{"bank_alias":"尉氏合益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006223"},{"bank_alias":"海南昌江长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006224"},{"bank_alias":"临颍中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006225"},{"bank_alias":"江苏高淳武家嘴中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006226"},{"bank_alias":"定州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006227"},{"bank_alias":"魏县齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006228"},{"bank_alias":"通化东昌榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006230"},{"bank_alias":"鹿泉恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006231"},{"bank_alias":"临沂河东齐商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006232"},{"bank_alias":"临川浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006233"},{"bank_alias":"辛集齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006234"},{"bank_alias":"玉溪澄江中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006235"},{"bank_alias":"金堂汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006236"},{"bank_alias":"哈尔滨呼兰浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006237"},{"bank_alias":"湖南洞口潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006238"},{"bank_alias":"长葛轩辕村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006239"},{"bank_alias":"福建闽清瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006240"},{"bank_alias":"新乡中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006242"},{"bank_alias":"江苏溧水民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006243"},{"bank_alias":"瑞丽沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006244"},{"bank_alias":"湖南攸县潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006245"},{"bank_alias":"兴县汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006246"},{"bank_alias":"新都桂城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006247"},{"bank_alias":"重庆大足汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006248"},{"bank_alias":"浙江台州黄岩恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006249"},{"bank_alias":"乐陵圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006250"},{"bank_alias":"阿拉善左旗黄河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006251"},{"bank_alias":"安徽霍山联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006252"},{"bank_alias":"土默特左旗金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006253"},{"bank_alias":"辽宁义县锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006254"},{"bank_alias":"浙江德清湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006255"},{"bank_alias":"达拉特中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006256"},{"bank_alias":"海南儋州绿色村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006257"},{"bank_alias":"玉屏长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006258"},{"bank_alias":"宁波海曙浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006260"},{"bank_alias":"兴义万丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006261"},{"bank_alias":"象山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006262"},{"bank_alias":"安徽五河永泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006263"},{"bank_alias":"建湖中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006264"},{"bank_alias":"江苏靖江润丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006265"},{"bank_alias":"清徐惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006266"},{"bank_alias":"嫩江幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006267"},{"bank_alias":"临江蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006268"},{"bank_alias":"安徽谯城湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006269"},{"bank_alias":"陕西周至农科村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006270"},{"bank_alias":"九台龙嘉村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006271"},{"bank_alias":"来宾象州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006272"},{"bank_alias":"福建漳平民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006273"},{"bank_alias":"山东商河汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006275"},{"bank_alias":"福建福鼎恒兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006276"},{"bank_alias":"常州新北中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006277"},{"bank_alias":"汕头龙湖长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006278"},{"bank_alias":"宁夏永宁汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006280"},{"bank_alias":"元谋兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006281"},{"bank_alias":"深州丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006282"},{"bank_alias":"安徽岳西湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006283"},{"bank_alias":"张家口崇礼邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006284"},{"bank_alias":"余干恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006285"},{"bank_alias":"鄯善中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006286"},{"bank_alias":"蒙自沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006287"},{"bank_alias":"德庆华润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006288"},{"bank_alias":"河南沁阳江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006289"},{"bank_alias":"彭泽九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006290"},{"bank_alias":"保山昌宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006291"},{"bank_alias":"单县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006292"},{"bank_alias":"文山富宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006293"},{"bank_alias":"青海平安大通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006294"},{"bank_alias":"开鲁蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006295"},{"bank_alias":"湖北公安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006297"},{"bank_alias":"天津武清村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006298"},{"bank_alias":"宣汉诚民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006299"},{"bank_alias":"全椒中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006300"},{"bank_alias":"济宁蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006301"},{"bank_alias":"陕西岐山长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006302"},{"bank_alias":"南和融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006303"},{"bank_alias":"雄县丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006304"},{"bank_alias":"天津静海新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006305"},{"bank_alias":"响水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006306"},{"bank_alias":"凌源天元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006307"},{"bank_alias":"福建武平杭兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006308"},{"bank_alias":"微山北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006309"},{"bank_alias":"青海门源大通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006310"},{"bank_alias":"湖北大冶泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006311"},{"bank_alias":"瑞昌九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006312"},{"bank_alias":"长垣民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006313"},{"bank_alias":"抚顺新宾抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006314"},{"bank_alias":"赫章富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006315"},{"bank_alias":"安义融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006316"},{"bank_alias":"章丘齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006317"},{"bank_alias":"江西婺源江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006318"},{"bank_alias":"陕西吴起汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006319"},{"bank_alias":"清远清新惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006320"},{"bank_alias":"哈尔滨农信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006321"},{"bank_alias":"陵川县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006322"},{"bank_alias":"汾阳市九都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006323"},{"bank_alias":"济源齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006324"},{"bank_alias":"江苏武进中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006325"},{"bank_alias":"衡水冀州丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006326"},{"bank_alias":"塔城津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006327"},{"bank_alias":"济宁儒商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006328"},{"bank_alias":"福建福安渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006329"},{"bank_alias":"湖南溆浦湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006330"},{"bank_alias":"扎赉特蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006331"},{"bank_alias":"庐江惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006332"},{"bank_alias":"保山隆阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006333"},{"bank_alias":"长汀汀州红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006334"},{"bank_alias":"本溪丰泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006335"},{"bank_alias":"广西兴业柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006336"},{"bank_alias":"南昌昌东九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006337"},{"bank_alias":"南京浦口靖发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006338"},{"bank_alias":"乾县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006339"},{"bank_alias":"靖安九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006340"},{"bank_alias":"密山民意村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006341"},{"bank_alias":"福建诏安汇通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006342"},{"bank_alias":"固始天骄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006343"},{"bank_alias":"唐山市开平汇金村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006345"},{"bank_alias":"菏泽牡丹北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006346"},{"bank_alias":"武乡县泽都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006347"},{"bank_alias":"上海浦东江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006348"},{"bank_alias":"济南长清沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006349"},{"bank_alias":"柘城黄淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006350"},{"bank_alias":"武汉东西湖扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006351"},{"bank_alias":"中江融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006352"},{"bank_alias":"石家庄栾城齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006353"},{"bank_alias":"宜黄抚商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006354"},{"bank_alias":"青岛西海岸海汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006355"},{"bank_alias":"新疆石河子市交银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006356"},{"bank_alias":"江苏张家港渝农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006357"},{"bank_alias":"安徽广德扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006359"},{"bank_alias":"兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006360"},{"bank_alias":"新余孔目江成功村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006362"},{"bank_alias":"湖南东安星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006363"},{"bank_alias":"镇江润州长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006364"},{"bank_alias":"江苏邳州陇海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006365"},{"bank_alias":"丽江古城富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006366"},{"bank_alias":"漯河市郾城包商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006367"},{"bank_alias":"盐城滨海兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006369"},{"bank_alias":"浑源县慧融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006370"},{"bank_alias":"浙江江山中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006371"},{"bank_alias":"安徽东至扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006372"},{"bank_alias":"沁源县长青村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006373"},{"bank_alias":"侯马市太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006374"},{"bank_alias":"剑河富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006375"},{"bank_alias":"昆明马金铺中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006376"},{"bank_alias":"上饶中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006377"},{"bank_alias":"余庆中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006378"},{"bank_alias":"南宁兴宁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006379"},{"bank_alias":"昆明宜良融丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006380"},{"bank_alias":"施秉金鼎村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006381"},{"bank_alias":"江西赣州银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006382"},{"bank_alias":"营口宏诚村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006383"},{"bank_alias":"中牟郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006384"},{"bank_alias":"长阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006385"},{"bank_alias":"曲靖惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006387"},{"bank_alias":"宁波奉化罗蒙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006388"},{"bank_alias":"宁波北仑中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006389"},{"bank_alias":"黔西南义龙浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006390"},{"bank_alias":"石家庄新华恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006391"},{"bank_alias":"山东肥城民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006393"},{"bank_alias":"舒兰吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006394"},{"bank_alias":"永靖县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006395"},{"bank_alias":"兰西农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006396"},{"bank_alias":"天水秦州长银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006397"},{"bank_alias":"河北丰宁中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006399"},{"bank_alias":"江西高安富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006400"},{"bank_alias":"扶沟郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006401"},{"bank_alias":"涿鹿利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006402"},{"bank_alias":"清徐晋商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006403"},{"bank_alias":"大通中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006404"},{"bank_alias":"常宁珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006405"},{"bank_alias":"昆明五华长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006407"},{"bank_alias":"重庆垫江中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006408"},{"bank_alias":"万荣县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006409"},{"bank_alias":"普洱民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006410"},{"bank_alias":"介休市华都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006412"},{"bank_alias":"陕西旬阳泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006413"},{"bank_alias":"中山古镇南粤村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006416"},{"bank_alias":"上海松江富明村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006417"},{"bank_alias":"澧县沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006418"},{"bank_alias":"桐梓中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006419"},{"bank_alias":"江西芦溪富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006420"},{"bank_alias":"荆门东宝惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006421"},{"bank_alias":"浙江衢州衢江上银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006422"},{"bank_alias":"江西信州江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006424"},{"bank_alias":"宜丰中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006426"},{"bank_alias":"扎兰屯蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006427"},{"bank_alias":"滦平盛阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006428"},{"bank_alias":"淮安清浦兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006429"},{"bank_alias":"泌阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006430"},{"bank_alias":"灵石县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006431"},{"bank_alias":"宣化中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006432"},{"bank_alias":"宁安融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006433"},{"bank_alias":"上海嘉定民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006434"},{"bank_alias":"浙江洞头富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006435"},{"bank_alias":"郧县楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006436"},{"bank_alias":"茶陵浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006437"},{"bank_alias":"团风楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006439"},{"bank_alias":"开阳富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006440"},{"bank_alias":"潮州潮安长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006441"},{"bank_alias":"浙江建德湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006442"},{"bank_alias":"习水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006443"},{"bank_alias":"江苏淮安光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006444"},{"bank_alias":"山东新泰齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006445"},{"bank_alias":"蔚县银泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006446"},{"bank_alias":"惠州博罗长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006447"},{"bank_alias":"南昌大丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006448"},{"bank_alias":"广州白云民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006450"},{"bank_alias":"临县泉都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006452"},{"bank_alias":"云浮新兴东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006453"},{"bank_alias":"周宁刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006454"},{"bank_alias":"嵩明沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006455"},{"bank_alias":"德惠敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006456"},{"bank_alias":"榆林榆阳民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006457"},{"bank_alias":"包头市昆都仑蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006458"},{"bank_alias":"印江长征村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006459"},{"bank_alias":"湖南湘潭湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006460"},{"bank_alias":"白城洮北惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006461"},{"bank_alias":"仁寿民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006462"},{"bank_alias":"惠州仲恺东盈村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006464"},{"bank_alias":"东山润鑫村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006465"},{"bank_alias":"福建大田晋农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006466"},{"bank_alias":"寿阳县汇都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006467"},{"bank_alias":"海口苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006468"},{"bank_alias":"上海宝山富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006470"},{"bank_alias":"灵川深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006471"},{"bank_alias":"鄂托克旗汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006472"},{"bank_alias":"泸水中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006473"},{"bank_alias":"张北信达村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006474"},{"bank_alias":"蕲春中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006478"},{"bank_alias":"云梦楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006479"},{"bank_alias":"柏乡融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006480"},{"bank_alias":"安塞农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006481"},{"bank_alias":"陕西柞水聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006483"},{"bank_alias":"许昌新浦村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006484"},{"bank_alias":"大连金州联丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006485"},{"bank_alias":"江苏涟水太商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006486"},{"bank_alias":"宜都民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006487"},{"bank_alias":"深圳龙岗中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006488"},{"bank_alias":"阆中融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006489"},{"bank_alias":"神池县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006490"},{"bank_alias":"内黄兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006491"},{"bank_alias":"怀来利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006493"},{"bank_alias":"甘肃西固金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006494"},{"bank_alias":"江川兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006495"},{"bank_alias":"临沭民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006496"},{"bank_alias":"延吉和润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006497"},{"bank_alias":"江苏邗江联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006498"},{"bank_alias":"湖北随州曾都汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006499"},{"bank_alias":"兰州皋兰新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006500"},{"bank_alias":"桦甸惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006501"},{"bank_alias":"巴彦淖尔市乌拉特村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006502"},{"bank_alias":"普定富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006503"},{"bank_alias":"兴平中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006504"},{"bank_alias":"乐安洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006505"},{"bank_alias":"常州钟楼长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006507"},{"bank_alias":"农安北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006508"},{"bank_alias":"宁陵德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006509"},{"bank_alias":"汪清和润村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006510"},{"bank_alias":"文山丘北长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006511"},{"bank_alias":"北京密云汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006512"},{"bank_alias":"湖北英山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006513"},{"bank_alias":"岳池中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006514"},{"bank_alias":"陕西泾阳泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006515"},{"bank_alias":"分宜九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006516"},{"bank_alias":"龙井榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006517"},{"bank_alias":"慈溪民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006518"},{"bank_alias":"卫辉富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006519"},{"bank_alias":"河南新野中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006520"},{"bank_alias":"平罗沙湖村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006521"},{"bank_alias":"曹县中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006522"},{"bank_alias":"济南高新北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006523"},{"bank_alias":"织金惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006524"},{"bank_alias":"永寿中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006525"},{"bank_alias":"福建建瓯瑞狮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006526"},{"bank_alias":"荔波富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006527"},{"bank_alias":"建水沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006528"},{"bank_alias":"贵阳南明富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006529"},{"bank_alias":"长春绿园融泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006530"},{"bank_alias":"古交市汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006531"},{"bank_alias":"新绛县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006532"},{"bank_alias":"浙江云和联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006533"},{"bank_alias":"玉田大商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006534"},{"bank_alias":"什邡思源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006535"},{"bank_alias":"湖南沅陵新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006536"},{"bank_alias":"东辽农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006537"},{"bank_alias":"汝州玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006538"},{"bank_alias":"陕西户县海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006539"},{"bank_alias":"筠连中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006540"},{"bank_alias":"德宏芒市长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006541"},{"bank_alias":"四平辽河蛟银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006542"},{"bank_alias":"平塘富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006543"},{"bank_alias":"曲靖沾益兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006544"},{"bank_alias":"辽宁彰武金通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006545"},{"bank_alias":"淳化中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006547"},{"bank_alias":"汤阴兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006548"},{"bank_alias":"柳林汇泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006549"},{"bank_alias":"都昌九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006550"},{"bank_alias":"民权德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006551"},{"bank_alias":"青岛平度惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006552"},{"bank_alias":"隆德六盘山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006553"},{"bank_alias":"湖南宁远潭农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006555"},{"bank_alias":"阳新汉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006556"},{"bank_alias":"武隆融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006557"},{"bank_alias":"上海浦东中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006558"},{"bank_alias":"浙江东阳富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006559"},{"bank_alias":"安徽郎溪新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006560"},{"bank_alias":"昆明禄劝中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006561"},{"bank_alias":"文安县惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006562"},{"bank_alias":"汾西县太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006563"},{"bank_alias":"安徽黄山金桥村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006564"},{"bank_alias":"襄汾县万都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006565"},{"bank_alias":"霍林郭勒蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006566"},{"bank_alias":"乌海千里山河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006568"},{"bank_alias":"宁夏宁东本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006569"},{"bank_alias":"赤城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006570"},{"bank_alias":"磴口蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006571"},{"bank_alias":"北京顺义银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006572"},{"bank_alias":"安徽怀远本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006573"},{"bank_alias":"山东泗水齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006574"},{"bank_alias":"包头市东河金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006575"},{"bank_alias":"正安中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006576"},{"bank_alias":"江西瑞金光大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006577"},{"bank_alias":"辽宁首山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006578"},{"bank_alias":"黑龙江肇东中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006579"},{"bank_alias":"晋州恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006580"},{"bank_alias":"永吉吉庆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006581"},{"bank_alias":"浙江龙游义商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006582"},{"bank_alias":"南城富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006584"},{"bank_alias":"宜章长行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006586"},{"bank_alias":"寻甸中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006587"},{"bank_alias":"田阳兴阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006588"},{"bank_alias":"包头青山河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006589"},{"bank_alias":"山东蒙阴齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006590"},{"bank_alias":"犍为中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006591"},{"bank_alias":"湖南桃源湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006592"},{"bank_alias":"广丰广信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006593"},{"bank_alias":"赞皇隆兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006594"},{"bank_alias":"迁安襄隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006595"},{"bank_alias":"峡江洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006596"},{"bank_alias":"泽州浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006597"},{"bank_alias":"福建龙海泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006598"},{"bank_alias":"珲春吉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006600"},{"bank_alias":"青岛胶州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006601"},{"bank_alias":"青州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006602"},{"bank_alias":"中山小榄村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006603"},{"bank_alias":"江苏通州华商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006604"},{"bank_alias":"广西柳江柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006605"},{"bank_alias":"陆良兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006606"},{"bank_alias":"浙江岱山稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006607"},{"bank_alias":"浙江温岭联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006608"},{"bank_alias":"凤城丰益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006610"},{"bank_alias":"浙江嵊州瑞丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006611"},{"bank_alias":"扶绥深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006612"},{"bank_alias":"武邑邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006613"},{"bank_alias":"湖北咸安武农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006614"},{"bank_alias":"山东滕州中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006615"},{"bank_alias":"信阳珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006617"},{"bank_alias":"安徽当涂新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006618"},{"bank_alias":"修文江海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006619"},{"bank_alias":"宁晋民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006620"},{"bank_alias":"白银平川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006622"},{"bank_alias":"安国中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006623"},{"bank_alias":"安徽金寨江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006624"},{"bank_alias":"乾安惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006625"},{"bank_alias":"陕西眉县泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006626"},{"bank_alias":"隰县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006627"},{"bank_alias":"江苏如东融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006628"},{"bank_alias":"鄂尔多斯市罕台村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006629"},{"bank_alias":"长白榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006630"},{"bank_alias":"宝清广益村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006631"},{"bank_alias":"淮阳中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006632"},{"bank_alias":"深圳南山宝生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006633"},{"bank_alias":"福建连城杭兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006635"},{"bank_alias":"高平市太行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006637"},{"bank_alias":"九江庐山浔银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006638"},{"bank_alias":"安徽泾县铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006639"},{"bank_alias":"江苏邗江民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006640"},{"bank_alias":"宜宾兴宜村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006641"},{"bank_alias":"湘西长行村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006642"},{"bank_alias":"扬州高邮兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006643"},{"bank_alias":"六盘水六枝富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006644"},{"bank_alias":"银川掌政石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006645"},{"bank_alias":"渑池齐鲁村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006646"},{"bank_alias":"重庆江津石银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006647"},{"bank_alias":"宁阳沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006648"},{"bank_alias":"重庆渝北银座村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006649"},{"bank_alias":"沈阳康平抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006650"},{"bank_alias":"高密惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006651"},{"bank_alias":"潍坊市潍城区北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006652"},{"bank_alias":"宁夏平罗县沙湖村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006653"},{"bank_alias":"安徽宣州湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006654"},{"bank_alias":"湖北天门汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006655"},{"bank_alias":"抚顺顺城抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006656"},{"bank_alias":"江苏惠山民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006657"},{"bank_alias":"江西莲花富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006658"},{"bank_alias":"建昌恒昌村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006659"},{"bank_alias":"新余渝水湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006660"},{"bank_alias":"宜阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006661"},{"bank_alias":"禄丰龙城富滇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006662"},{"bank_alias":"邻水中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006664"},{"bank_alias":"永丰洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006665"},{"bank_alias":"奉新九银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006666"},{"bank_alias":"山东冠县齐丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006667"},{"bank_alias":"青岛黄岛舜丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006668"},{"bank_alias":"遂川洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006669"},{"bank_alias":"贵阳花溪建设村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006670"},{"bank_alias":"阳曲县汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006672"},{"bank_alias":"湄潭中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006674"},{"bank_alias":"辽宁黑山锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006675"},{"bank_alias":"丽江永胜长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006676"},{"bank_alias":"文山广南长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006677"},{"bank_alias":"定兴丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006678"},{"bank_alias":"琼海大众村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006679"},{"bank_alias":"成都青白江融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006680"},{"bank_alias":"广昌南银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006682"},{"bank_alias":"涞水利丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006683"},{"bank_alias":"湖南汉寿星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006684"},{"bank_alias":"玉山三清山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006685"},{"bank_alias":"湖南衡东新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006686"},{"bank_alias":"重庆市酉阳融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006687"},{"bank_alias":"浦城中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006688"},{"bank_alias":"尉犁达西冀银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006689"},{"bank_alias":"原平市汇民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006690"},{"bank_alias":"汉中汉台铺镇聚利村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006691"},{"bank_alias":"珠海南屏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006692"},{"bank_alias":"贵阳乌当富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006693"},{"bank_alias":"凤冈中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006694"},{"bank_alias":"江门新会新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006695"},{"bank_alias":"塔城昆仑村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006696"},{"bank_alias":"安达幸福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006697"},{"bank_alias":"赤峰市红山玉龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006698"},{"bank_alias":"古交市阜民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006699"},{"bank_alias":"孟州射阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006700"},{"bank_alias":"山东招远中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006701"},{"bank_alias":"浙江柯桥联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006702"},{"bank_alias":"江苏赣榆通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006703"},{"bank_alias":"涿州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006704"},{"bank_alias":"广州从化柳银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006705"},{"bank_alias":"朔州市朔城区蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006707"},{"bank_alias":"江苏射阳太商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006708"},{"bank_alias":"重庆梁平澳新村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006709"},{"bank_alias":"集贤润生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006712"},{"bank_alias":"江陵楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006713"},{"bank_alias":"新疆库尔勒富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006714"},{"bank_alias":"兴宁珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006715"},{"bank_alias":"平山西柏坡冀银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006716"},{"bank_alias":"陕西临潼海丝村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006717"},{"bank_alias":"江苏铜山锡州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006718"},{"bank_alias":"天水麦积融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006719"},{"bank_alias":"海南澄迈长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006720"},{"bank_alias":"海南屯昌长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006721"},{"bank_alias":"吴桥融信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006723"},{"bank_alias":"丹东鼎元村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006724"},{"bank_alias":"昆明东川中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006725"},{"bank_alias":"青海湟中三江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006726"},{"bank_alias":"长武中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006727"},{"bank_alias":"浙江临安中信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006728"},{"bank_alias":"兖州中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006729"},{"bank_alias":"重庆永川北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006731"},{"bank_alias":"吉林船营惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006732"},{"bank_alias":"宜州深通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006734"},{"bank_alias":"伊通榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006735"},{"bank_alias":"安顺西秀富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006736"},{"bank_alias":"浙江乐清联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006738"},{"bank_alias":"江阴浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006739"},{"bank_alias":"合水县金城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006740"},{"bank_alias":"芜湖圆融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006741"},{"bank_alias":"北京房山沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006742"},{"bank_alias":"湖南蓝山神农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006743"},{"bank_alias":"阳高县兴都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006744"},{"bank_alias":"安陆楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006745"},{"bank_alias":"江苏宝应锦程村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006746"},{"bank_alias":"重庆九龙坡民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006747"},{"bank_alias":"北京平谷新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006748"},{"bank_alias":"平陆县河东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006749"},{"bank_alias":"淄博博山北海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006750"},{"bank_alias":"山东荣成汇丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006751"},{"bank_alias":"蒲城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006752"},{"bank_alias":"洪洞县洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006754"},{"bank_alias":"乐亭舜丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006755"},{"bank_alias":"东莞厚街华业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006756"},{"bank_alias":"龙里国丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006757"},{"bank_alias":"江苏海安盐海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006758"},{"bank_alias":"安徽宿州淮海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006760"},{"bank_alias":"大冶中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006761"},{"bank_alias":"佛山南海新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006765"},{"bank_alias":"故城家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006766"},{"bank_alias":"安徽石台扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006767"},{"bank_alias":"潍坊市奎文区中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006768"},{"bank_alias":"广安恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006769"},{"bank_alias":"楚雄红塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006770"},{"bank_alias":"丹东福汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006771"},{"bank_alias":"常州金坛兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006772"},{"bank_alias":"辽宁沈东村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006773"},{"bank_alias":"广州黄埔惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006774"},{"bank_alias":"建宁刺桐红村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006775"},{"bank_alias":"靖宇乾丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006776"},{"bank_alias":"崇左大新长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006777"},{"bank_alias":"太仆寺旗鑫源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006778"},{"bank_alias":"江苏沛县汉源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006779"},{"bank_alias":"和龙敦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006780"},{"bank_alias":"宁国民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006781"},{"bank_alias":"宁波镇海中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006782"},{"bank_alias":"广元市贵商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006783"},{"bank_alias":"滨州河海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006784"},{"bank_alias":"包头市九原立农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006785"},{"bank_alias":"宁夏青铜峡贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006786"},{"bank_alias":"江苏东台稠州村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006787"},{"bank_alias":"应县金都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006788"},{"bank_alias":"广东四会泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006789"},{"bank_alias":"鄂尔多斯市东胜蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006790"},{"bank_alias":"安徽和县新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006792"},{"bank_alias":"宜城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006794"},{"bank_alias":"深圳宝安桂银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006795"},{"bank_alias":"绥中长丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006796"},{"bank_alias":"辽宁千山金泉村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006797"},{"bank_alias":"巨野中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006799"},{"bank_alias":"长沙星沙沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006800"},{"bank_alias":"梨树源泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006801"},{"bank_alias":"呼和浩特市如意蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006802"},{"bank_alias":"天津西青中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006803"},{"bank_alias":"丹江口楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006804"},{"bank_alias":"淇县中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006805"},{"bank_alias":"呼和浩特金桥河套村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006807"},{"bank_alias":"天津津南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006808"},{"bank_alias":"永修浔银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006809"},{"bank_alias":"景县丰源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006810"},{"bank_alias":"虞城通商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006811"},{"bank_alias":"雷州惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006812"},{"bank_alias":"沅江浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006813"},{"bank_alias":"濮阳中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006814"},{"bank_alias":"乌拉特中旗蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006815"},{"bank_alias":"南宁马山长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006818"},{"bank_alias":"东平沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006820"},{"bank_alias":"闻喜县晋融村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006821"},{"bank_alias":"大连旅顺口蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006822"},{"bank_alias":"汝阳兴福村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006823"},{"bank_alias":"大连保税区珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006824"},{"bank_alias":"南部县中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006825"},{"bank_alias":"扶余惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006826"},{"bank_alias":"重庆南岸中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006827"},{"bank_alias":"鄂托克兴生源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006828"},{"bank_alias":"孟津民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006830"},{"bank_alias":"东莞黄江珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006831"},{"bank_alias":"陇西神舟村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006832"},{"bank_alias":"山东诸城中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006833"},{"bank_alias":"兴山本富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006834"},{"bank_alias":"安徽歙县嘉银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006835"},{"bank_alias":"都匀融通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006836"},{"bank_alias":"天津滨海扬子村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006837"},{"bank_alias":"株洲县融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006838"},{"bank_alias":"沧州盐山新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006839"},{"bank_alias":"舞阳玉川村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006840"},{"bank_alias":"天津滨海惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006842"},{"bank_alias":"重庆市大渡口融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006843"},{"bank_alias":"重庆市武隆融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006844"},{"bank_alias":"西安雁塔恒通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006845"},{"bank_alias":"阿拉善左旗方大村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006846"},{"bank_alias":"遂宁安居融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006847"},{"bank_alias":"安康汉滨中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006848"},{"bank_alias":"四川北川羌族自治县富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006849"},{"bank_alias":"浚县郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006850"},{"bank_alias":"南陵太平村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006851"},{"bank_alias":"广西兴安民兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006852"},{"bank_alias":"山东金乡蓝海村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006853"},{"bank_alias":"四川成都蒲江民富村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006854"},{"bank_alias":"耒阳融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006855"},{"bank_alias":"远安金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006857"},{"bank_alias":"临泉中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006858"},{"bank_alias":"浙江桐乡民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006859"},{"bank_alias":"弥勒沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006860"},{"bank_alias":"隆尧邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006861"},{"bank_alias":"罗田楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006862"},{"bank_alias":"突泉蒙银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006863"},{"bank_alias":"北京怀柔融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006865"},{"bank_alias":"龙口中银富登南山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006866"},{"bank_alias":"卢龙家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006867"},{"bank_alias":"莱州珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006868"},{"bank_alias":"确山郑银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006869"},{"bank_alias":"东源泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006870"},{"bank_alias":"吉林昌邑榆银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006871"},{"bank_alias":"北京延庆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006872"},{"bank_alias":"北京大兴华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006873"},{"bank_alias":"安徽利辛湖商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006874"},{"bank_alias":"榆树融兴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006875"},{"bank_alias":"太仓民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006876"},{"bank_alias":"大名恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006877"},{"bank_alias":"石首楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006878"},{"bank_alias":"浙江遂昌富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006879"},{"bank_alias":"四川江油华夏村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006880"},{"bank_alias":"玉溪红塔村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006881"},{"bank_alias":"西双版纳勐腊长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006882"},{"bank_alias":"扶风浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006883"},{"bank_alias":"抚顺望花抚银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006884"},{"bank_alias":"铁门关津汇村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006885"},{"bank_alias":"湖南安化湘淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006886"},{"bank_alias":"昆山鹿城村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006887"},{"bank_alias":"吉县新田村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006888"},{"bank_alias":"关岭恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006889"},{"bank_alias":"衡南浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006891"},{"bank_alias":"绵竹浦发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006892"},{"bank_alias":"贞丰兴贞村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006893"},{"bank_alias":"昆明石林中成村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006894"},{"bank_alias":"栖霞中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006895"},{"bank_alias":"云南新平北银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006896"},{"bank_alias":"安福中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006897"},{"bank_alias":"珠海横琴村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006898"},{"bank_alias":"泰安沪农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006899"},{"bank_alias":"范县德商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006901"},{"bank_alias":"陕西富平汇发村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006902"},{"bank_alias":"达州达川中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006903"},{"bank_alias":"鄂尔多斯市塔拉壕金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006904"},{"bank_alias":"浙江庆元泰隆村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006905"},{"bank_alias":"山东博兴新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006906"},{"bank_alias":"湖南湘阴星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006907"},{"bank_alias":"扬中恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006908"},{"bank_alias":"深圳坪山珠江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006909"},{"bank_alias":"安徽固镇新淮河村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006910"},{"bank_alias":"保山施甸长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006911"},{"bank_alias":"安徽祁门铜源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006912"},{"bank_alias":"浙江缙云联合村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006913"},{"bank_alias":"上蔡惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006914"},{"bank_alias":"浙江台州路桥富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006915"},{"bank_alias":"昌黎家银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006916"},{"bank_alias":"安徽太湖江淮村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006917"},{"bank_alias":"丽江玉龙长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006918"},{"bank_alias":"通榆农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006919"},{"bank_alias":"山东文登中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006920"},{"bank_alias":"安徽宿松民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006922"},{"bank_alias":"兴化苏南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006923"},{"bank_alias":"湖南隆回湘江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006924"},{"bank_alias":"康保银丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006925"},{"bank_alias":"宁夏惠农贺兰山村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006926"},{"bank_alias":"陕西安塞中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006927"},{"bank_alias":"五大连池惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006928"},{"bank_alias":"文山民丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006930"},{"bank_alias":"重庆江北恒丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006931"},{"bank_alias":"万安洪都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006932"},{"bank_alias":"大理洱源长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006935"},{"bank_alias":"浙江龙泉民泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006936"},{"bank_alias":"广州番禺新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006937"},{"bank_alias":"湖北赤壁长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006938"},{"bank_alias":"湛江廉江长江村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006939"},{"bank_alias":"沧州海兴新华村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006940"},{"bank_alias":"漳浦民生村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006941"},{"bank_alias":"湖南安仁新阳村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006942"},{"bank_alias":"邢台县邢农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006943"},{"bank_alias":"敦化江南村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006944"},{"bank_alias":"辽宁凌海锦银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006945"},{"bank_alias":"东明中银富登村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006946"},{"bank_alias":"惠东惠民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006947"},{"bank_alias":"邯郸肥乡恒升村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006948"},{"bank_alias":"清河金农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006949"},{"bank_alias":"营口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006950"},{"bank_alias":"广东海丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006953"},{"bank_alias":"湖南嘉禾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006957"},{"bank_alias":"湖南新宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006958"},{"bank_alias":"四川三台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006960"},{"bank_alias":"湖南耒阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006964"},{"bank_alias":"河北张北农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006966"},{"bank_alias":"四川绵竹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006968"},{"bank_alias":"白山江源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006970"},{"bank_alias":"四川岳池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006971"},{"bank_alias":"四川富顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006973"},{"bank_alias":"湖南会同农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006974"},{"bank_alias":"河北安平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006975"},{"bank_alias":"湖南临澧农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006977"},{"bank_alias":"河北怀来农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006978"},{"bank_alias":"吉林春城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006979"},{"bank_alias":"营口融生农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006980"},{"bank_alias":"湖南新田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006982"},{"bank_alias":"湖南沅江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006984"},{"bank_alias":"张家界农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006985"},{"bank_alias":"河北万全农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006986"},{"bank_alias":"江苏常熟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006987"},{"bank_alias":"宜宾翠屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006988"},{"bank_alias":"吉林舒兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006989"},{"bank_alias":"贵州息烽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006990"},{"bank_alias":"常德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006992"},{"bank_alias":"眉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006993"},{"bank_alias":"四川大竹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006995"},{"bank_alias":"辽宁大石桥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006996"},{"bank_alias":"长白山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006997"},{"bank_alias":"潮州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000006998"},{"bank_alias":"延边农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007000"},{"bank_alias":"永州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007001"},{"bank_alias":"四川仁寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007002"},{"bank_alias":"四川青川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007003"},{"bank_alias":"长沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007004"},{"bank_alias":"吉林德惠农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007007"},{"bank_alias":"江苏昆山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007008"},{"bank_alias":"湖南湘阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007010"},{"bank_alias":"贵州从江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007011"},{"bank_alias":"吉林安图农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007013"},{"bank_alias":"河北蠡州北银农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007017"},{"bank_alias":"贵州紫云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007018"},{"bank_alias":"湖南靖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007019"},{"bank_alias":"四川剑阁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007020"},{"bank_alias":"沈阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007021"},{"bank_alias":"河北任县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007022"},{"bank_alias":"辽宁大洼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007023"},{"bank_alias":"辽宁建平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007026"},{"bank_alias":"四川兴文石海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007027"},{"bank_alias":"吉林东丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007028"},{"bank_alias":"湖南溆浦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007029"},{"bank_alias":"贵州毕节农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007031"},{"bank_alias":"湖南宁远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007034"},{"bank_alias":"石家庄鹿泉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007036"},{"bank_alias":"湖南通道农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007037"},{"bank_alias":"吉林临江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007038"},{"bank_alias":"河北南和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007042"},{"bank_alias":"河北香河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007043"},{"bank_alias":"辽宁灯塔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007044"},{"bank_alias":"吉林和龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007045"},{"bank_alias":"河北景州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007046"},{"bank_alias":"河北唐山曹妃甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007047"},{"bank_alias":"贵州兴义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007049"},{"bank_alias":"四川安州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007050"},{"bank_alias":"河北邯郸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007051"},{"bank_alias":"丹东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007052"},{"bank_alias":"湖南湘乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007055"},{"bank_alias":"湖南安乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007056"},{"bank_alias":"吉林龙井农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007057"},{"bank_alias":"湖南桂东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007060"},{"bank_alias":"河北涞水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007061"},{"bank_alias":"吉林珲春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007062"},{"bank_alias":"湖南衡山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007063"},{"bank_alias":"四川西充农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007065"},{"bank_alias":"吉林通化海科农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007066"},{"bank_alias":"张家口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007067"},{"bank_alias":"河北定州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007070"},{"bank_alias":"贵州独山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007071"},{"bank_alias":"湖南冷水江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007073"},{"bank_alias":"四川古蔺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007076"},{"bank_alias":"四川南部农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007077"},{"bank_alias":"吉林浑江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007078"},{"bank_alias":"河北滦州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007080"},{"bank_alias":"辽宁新民农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007081"},{"bank_alias":"贵州平塘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007084"},{"bank_alias":"太仓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007085"},{"bank_alias":"吉林汪清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007086"},{"bank_alias":"贵州花溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007087"},{"bank_alias":"贵州丹寨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007089"},{"bank_alias":"云南瑞丽南屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007091"},{"bank_alias":"湖南临武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007092"},{"bank_alias":"苏州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007093"},{"bank_alias":"河北晋州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007094"},{"bank_alias":"辽宁沈本农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007095"},{"bank_alias":"江苏江南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007096"},{"bank_alias":"四川蓬溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007097"},{"bank_alias":"河北柏乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007098"},{"bank_alias":"四川仪陇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007099"},{"bank_alias":"河北永清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007100"},{"bank_alias":"葫芦岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007101"},{"bank_alias":"贵州黔西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007102"},{"bank_alias":"湖南炎陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007103"},{"bank_alias":"河北邢台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007104"},{"bank_alias":"四川梓潼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007105"},{"bank_alias":"贵州湄潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007107"},{"bank_alias":"河北衡水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007108"},{"bank_alias":"湖南凤凰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007110"},{"bank_alias":"四川合江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007112"},{"bank_alias":"四川长宁竹海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007117"},{"bank_alias":"湖南花垣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007118"},{"bank_alias":"贵州余庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007119"},{"bank_alias":"湖南中方农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007120"},{"bank_alias":"四川筠连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007121"},{"bank_alias":"辽阳辽东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007122"},{"bank_alias":"吉林九台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007123"},{"bank_alias":"贵州兴仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007124"},{"bank_alias":"湖南祁东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007125"},{"bank_alias":"河北承德热河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007127"},{"bank_alias":"湖南常宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007128"},{"bank_alias":"宜宾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007129"},{"bank_alias":"铜仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007130"},{"bank_alias":"辽宁沈抚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007133"},{"bank_alias":"河北临城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007134"},{"bank_alias":"河北高碑店农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007137"},{"bank_alias":"贵州镇远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007138"},{"bank_alias":"成都农商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007140"},{"bank_alias":"河北三河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007141"},{"bank_alias":"衡阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007142"},{"bank_alias":"辽宁本溪南芬农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007143"},{"bank_alias":"辽宁盖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007144"},{"bank_alias":"河北井陉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007145"},{"bank_alias":"湖南麻阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007146"},{"bank_alias":"贵州黎平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007147"},{"bank_alias":"张家港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007148"},{"bank_alias":"贵州晴隆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007150"},{"bank_alias":"湘潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007151"},{"bank_alias":"湖南双峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007152"},{"bank_alias":"株洲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007153"},{"bank_alias":"湖南新邵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007154"},{"bank_alias":"湖南韶山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007155"},{"bank_alias":"贵州天柱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007156"},{"bank_alias":"河北玉田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007157"},{"bank_alias":"辽宁清原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007160"},{"bank_alias":"湖南古丈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007161"},{"bank_alias":"河北巨鹿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007163"},{"bank_alias":"江苏太仓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007164"},{"bank_alias":"四川叙永农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007167"},{"bank_alias":"广安思源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007168"},{"bank_alias":"贵州黄平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007169"},{"bank_alias":"河北南和农商行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007170"},{"bank_alias":"四川犍为农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007171"},{"bank_alias":"河北邢州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007172"},{"bank_alias":"湖南华容农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007173"},{"bank_alias":"湖南株洲珠江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007175"},{"bank_alias":"湖南衡东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007176"},{"bank_alias":"四川泸县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007177"},{"bank_alias":"湖南绥宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007179"},{"bank_alias":"湖南洪江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007180"},{"bank_alias":"河北卢龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007181"},{"bank_alias":"四川罗江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007182"},{"bank_alias":"河北唐山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007184"},{"bank_alias":"贵州惠水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007189"},{"bank_alias":"四川隆昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007191"},{"bank_alias":"河北保定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007193"},{"bank_alias":"四川屏山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007194"},{"bank_alias":"湖南汉寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007196"},{"bank_alias":"河北阳原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007197"},{"bank_alias":"宜宾南溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007198"},{"bank_alias":"贵州玉屏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007200"},{"bank_alias":"四川武胜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007203"},{"bank_alias":"河北滦平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007205"},{"bank_alias":"湖南城步农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007206"},{"bank_alias":"六盘水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007207"},{"bank_alias":"攀枝花农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007209"},{"bank_alias":"南充农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007210"},{"bank_alias":"湖南澧县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007211"},{"bank_alias":"湖南娄底农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007212"},{"bank_alias":"贵州三都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007213"},{"bank_alias":"贵州思南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007214"},{"bank_alias":"常熟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007216"},{"bank_alias":"河北宁晋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007218"},{"bank_alias":"湖南泸溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007219"},{"bank_alias":"河北大名农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007220"},{"bank_alias":"四川威远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007221"},{"bank_alias":"四川丹棱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007222"},{"bank_alias":"益阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007223"},{"bank_alias":"湖南永兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007224"},{"bank_alias":"吉林靖宇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007225"},{"bank_alias":"四川渠县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007226"},{"bank_alias":"遂宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007227"},{"bank_alias":"湖南永顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007228"},{"bank_alias":"四川广汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007230"},{"bank_alias":"雅安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007231"},{"bank_alias":"阳江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007232"},{"bank_alias":"吉林通榆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007235"},{"bank_alias":"湖南桂阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007236"},{"bank_alias":"湖南南岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007237"},{"bank_alias":"四川万源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007238"},{"bank_alias":"四川平武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007239"},{"bank_alias":"吉林辉南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007241"},{"bank_alias":"湖南道县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007242"},{"bank_alias":"湖南临湘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007243"},{"bank_alias":"湖南芷江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007244"},{"bank_alias":"自贡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007245"},{"bank_alias":"湖南东安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007246"},{"bank_alias":"贵州道真农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007247"},{"bank_alias":"河北献县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007248"},{"bank_alias":"贵州遵义汇川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007249"},{"bank_alias":"湖南湘潭天易农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007250"},{"bank_alias":"湖南祁阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007251"},{"bank_alias":"吉林环城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007252"},{"bank_alias":"吉林双阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007253"},{"bank_alias":"四川青神农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007254"},{"bank_alias":"河北涿鹿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007256"},{"bank_alias":"湖南安化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007259"},{"bank_alias":"凉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007262"},{"bank_alias":"吉林永吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007264"},{"bank_alias":"湖南桃江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007266"},{"bank_alias":"湖南辰溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007267"},{"bank_alias":"通化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007268"},{"bank_alias":"湖南岳阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007269"},{"bank_alias":"河北正定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007270"},{"bank_alias":"河北宽城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007271"},{"bank_alias":"吉林大安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007272"},{"bank_alias":"湖南星沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007273"},{"bank_alias":"鞍山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007274"},{"bank_alias":"湖南江华农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007275"},{"bank_alias":"湖南龙山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007276"},{"bank_alias":"贵州三穗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007279"},{"bank_alias":"吉林柳河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007281"},{"bank_alias":"河北沽源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007282"},{"bank_alias":"辽宁岫岩农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007283"},{"bank_alias":"内江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007284"},{"bank_alias":"湖南汨罗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007285"},{"bank_alias":"成都农商行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007287"},{"bank_alias":"四川阆中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007288"},{"bank_alias":"贵州桐梓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007290"},{"bank_alias":"湖南汝城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007291"},{"bank_alias":"辽阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007292"},{"bank_alias":"四川简阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007298"},{"bank_alias":"贵州遵义红花岗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007300"},{"bank_alias":"吉林公主岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007303"},{"bank_alias":"泸州江阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007305"},{"bank_alias":"长春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007306"},{"bank_alias":"湖南江永农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007307"},{"bank_alias":"河北深州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007308"},{"bank_alias":"四川苍溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007309"},{"bank_alias":"河北霸州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007310"},{"bank_alias":"吉林农安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007311"},{"bank_alias":"泸州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007313"},{"bank_alias":"贵州凤冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007315"},{"bank_alias":"湖南醴陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007316"},{"bank_alias":"怀化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007317"},{"bank_alias":"河北灵寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007318"},{"bank_alias":"湖南平江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007319"},{"bank_alias":"贵州赫章农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007324"},{"bank_alias":"长春发展农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007325"},{"bank_alias":"贵州安龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007327"},{"bank_alias":"吉林桦甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007328"},{"bank_alias":"广州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007329"},{"bank_alias":"河北涿州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007330"},{"bank_alias":"吉林镇赉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007333"},{"bank_alias":"贵州麻江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007334"},{"bank_alias":"贵州福泉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007335"},{"bank_alias":"湖南浏阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007336"},{"bank_alias":"河北黄骅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007338"},{"bank_alias":"贵州仁怀茅台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007339"},{"bank_alias":"湖南慈利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007341"},{"bank_alias":"重庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007343"},{"bank_alias":"四川射洪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007344"},{"bank_alias":"湖南衡南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007346"},{"bank_alias":"江苏张家港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007347"},{"bank_alias":"河北迁安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007351"},{"bank_alias":"郴州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007352"},{"bank_alias":"泸州龙马潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007353"},{"bank_alias":"湖南安仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007355"},{"bank_alias":"湖南蓝山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007356"},{"bank_alias":"辽宁新宾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007357"},{"bank_alias":"河北沙河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007359"},{"bank_alias":"吉林榆树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007361"},{"bank_alias":"湖南双牌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007362"},{"bank_alias":"湖南资兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007364"},{"bank_alias":"贵州都匀农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007365"},{"bank_alias":"贵州大方农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007366"},{"bank_alias":"吉林集安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007369"},{"bank_alias":"贵州普定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007370"},{"bank_alias":"吉林蛟河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007371"},{"bank_alias":"湖南津市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007372"},{"bank_alias":"河北滦南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007373"},{"bank_alias":"湖南桑植农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007374"},{"bank_alias":"河北固安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007375"},{"bank_alias":"河北元氏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007377"},{"bank_alias":"四川什邡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007378"},{"bank_alias":"贵州织金农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007379"},{"bank_alias":"湖南洞口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007380"},{"bank_alias":"辽宁宽甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007383"},{"bank_alias":"贵州乌当农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007385"},{"bank_alias":"贵州清镇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007387"},{"bank_alias":"锦州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007388"},{"bank_alias":"河北清河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007389"},{"bank_alias":"辽源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007393"},{"bank_alias":"河北文安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007395"},{"bank_alias":"广元农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007397"},{"bank_alias":"湖南南县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007399"},{"bank_alias":"河北辛集农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007401"},{"bank_alias":"四川峨眉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007402"},{"bank_alias":"贵州贵定农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007406"},{"bank_alias":"吉林磐石农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007407"},{"bank_alias":"湖南吉首农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007409"},{"bank_alias":"贵州普安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007410"},{"bank_alias":"河北涉县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007412"},{"bank_alias":"河北广宗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007413"},{"bank_alias":"四川华蓥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007414"},{"bank_alias":"湖南隆回农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007415"},{"bank_alias":"湖南攸县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007416"},{"bank_alias":"湖南桃源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007418"},{"bank_alias":"达州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007419"},{"bank_alias":"四川营山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007420"},{"bank_alias":"河北丰宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007421"},{"bank_alias":"巴中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007422"},{"bank_alias":"河北冀州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007423"},{"bank_alias":"河北阜城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007425"},{"bank_alias":"河北安国农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007427"},{"bank_alias":"四川高县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007428"},{"bank_alias":"湖南保靖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007430"},{"bank_alias":"昆山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007431"},{"bank_alias":"吉林郭尔罗斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007433"},{"bank_alias":"辽宁桓仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007434"},{"bank_alias":"辽宁海城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007435"},{"bank_alias":"河北临西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007436"},{"bank_alias":"辽宁兴城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007437"},{"bank_alias":"贵州遵义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007438"},{"bank_alias":"湖南省湘乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007439"},{"bank_alias":"湖南湘江新区农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007440"},{"bank_alias":"四川宣汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007441"},{"bank_alias":"辽宁凤城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007442"},{"bank_alias":"四川珙县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007445"},{"bank_alias":"四川邻水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007446"},{"bank_alias":"四川宜宾金江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007447"},{"bank_alias":"辽宁东港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007448"},{"bank_alias":"河北围场农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007450"},{"bank_alias":"江苏苏州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007452"},{"bank_alias":"贵州瓮安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007453"},{"bank_alias":"河北枣强农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007454"},{"bank_alias":"湖南宁乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007455"},{"bank_alias":"贵州龙里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007456"},{"bank_alias":"吉林敦化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007457"},{"bank_alias":"四川江安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007458"},{"bank_alias":"四川安岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007459"},{"bank_alias":"大连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007462"},{"bank_alias":"湖南石门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007467"},{"bank_alias":"湖南武冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007469"},{"bank_alias":"贵州贞丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007470"},{"bank_alias":"湖南沅陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007472"},{"bank_alias":"河北大厂农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007474"},{"bank_alias":"湖南邵阳昭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007477"},{"bank_alias":"江苏江阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007478"},{"bank_alias":"湖南茶陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007483"},{"bank_alias":"成都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007484"},{"bank_alias":"河北南皮农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007485"},{"bank_alias":"贵州荔波农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007487"},{"bank_alias":"资阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007488"},{"bank_alias":"安顺农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007489"},{"bank_alias":"河北平山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007491"},{"bank_alias":"邵阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007492"},{"bank_alias":"湖南宜章农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007494"},{"bank_alias":"河北武强农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007496"},{"bank_alias":"德阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007497"},{"bank_alias":"河北鸡泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007498"},{"bank_alias":"四川乐至农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007500"},{"bank_alias":"湖南新晃农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007503"},{"bank_alias":"湖南涟源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007504"},{"bank_alias":"河北张家口宣泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007505"},{"bank_alias":"四川大英农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007507"},{"bank_alias":"广安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007508"},{"bank_alias":"贵州关岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007509"},{"bank_alias":"河北沧州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007511"},{"bank_alias":"湖南新化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007512"},{"bank_alias":"湖南岳阳巴陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007515"},{"bank_alias":"湖南邵东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007516"},{"bank_alias":"海口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007517"},{"bank_alias":"贵州凯里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007519"},{"bank_alias":"贵州修文农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007520"},{"bank_alias":"贵州务川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007521"},{"bank_alias":"白城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007522"},{"bank_alias":"阜新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007523"},{"bank_alias":"湖南衡阳衡州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007524"},{"bank_alias":"阿合奇县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007531"},{"bank_alias":"本溪市桥头农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007532"},{"bank_alias":"江城哈尼族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007533"},{"bank_alias":"泸西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007534"},{"bank_alias":"汶川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007537"},{"bank_alias":"湖北恩施农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007538"},{"bank_alias":"云南大姚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007539"},{"bank_alias":"曲靖市沾益区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007544"},{"bank_alias":"江西广昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007545"},{"bank_alias":"康定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007546"},{"bank_alias":"湖北应城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007547"},{"bank_alias":"宜良县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007553"},{"bank_alias":"青海同仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007555"},{"bank_alias":"民丰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007558"},{"bank_alias":"资中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007559"},{"bank_alias":"宁夏青铜峡市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007561"},{"bank_alias":"江西赣县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007562"},{"bank_alias":"湖北鄂州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007563"},{"bank_alias":"江西樟树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007565"},{"bank_alias":"山东莱芜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007566"},{"bank_alias":"山东无棣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007568"},{"bank_alias":"于田县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007570"},{"bank_alias":"黑龙江抚远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007573"},{"bank_alias":"江西高安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007575"},{"bank_alias":"勐海县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007577"},{"bank_alias":"依兰县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007579"},{"bank_alias":"云南梁河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007581"},{"bank_alias":"得荣县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007586"},{"bank_alias":"抚顺县东四路农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007590"},{"bank_alias":"广平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007591"},{"bank_alias":"昆明市五华区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007593"},{"bank_alias":"新龙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007599"},{"bank_alias":"黑龙江省牡丹江市城郊农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007601"},{"bank_alias":"烟台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007604"},{"bank_alias":"察布查尔县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007607"},{"bank_alias":"本溪市市区兴达农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007611"},{"bank_alias":"云南昭通昭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007612"},{"bank_alias":"皮山县桑株乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007613"},{"bank_alias":"抚松县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007617"},{"bank_alias":"海林市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007618"},{"bank_alias":"宁安市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007620"},{"bank_alias":"宣威市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007623"},{"bank_alias":"江西芦溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007624"},{"bank_alias":"江西井冈山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007630"},{"bank_alias":"朝阳县新华路农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007631"},{"bank_alias":"山东禹城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007633"},{"bank_alias":"德州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007634"},{"bank_alias":"曲靖市马龙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007635"},{"bank_alias":"榕江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007640"},{"bank_alias":"黑龙江泰来农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007641"},{"bank_alias":"尼勒克县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007642"},{"bank_alias":"云南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007643"},{"bank_alias":"双辽市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007646"},{"bank_alias":"宁夏中宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007648"},{"bank_alias":"馆陶县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007649"},{"bank_alias":"昌江黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007653"},{"bank_alias":"山东临清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007656"},{"bank_alias":"张家口市宣化农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007657"},{"bank_alias":"寿光农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007658"},{"bank_alias":"黑龙江省望奎县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007661"},{"bank_alias":"青海民和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007662"},{"bank_alias":"疏附县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007664"},{"bank_alias":"山东乐陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007665"},{"bank_alias":"盐山县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007670"},{"bank_alias":"江西万年农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007671"},{"bank_alias":"江西泰和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007672"},{"bank_alias":"峨山彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007673"},{"bank_alias":"湖北孝感农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007675"},{"bank_alias":"江西庐山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007676"},{"bank_alias":"迁安市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007684"},{"bank_alias":"内丘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007685"},{"bank_alias":"济南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007686"},{"bank_alias":"赵县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007690"},{"bank_alias":"抚顺县拉古农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007691"},{"bank_alias":"云南云龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007692"},{"bank_alias":"江西黎川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007694"},{"bank_alias":"云南玉溪红塔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007698"},{"bank_alias":"山东平原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007701"},{"bank_alias":"云南宾川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007703"},{"bank_alias":"哈尔滨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007705"},{"bank_alias":"山东宁阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007706"},{"bank_alias":"皮山县杜瓦镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007711"},{"bank_alias":"中江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007712"},{"bank_alias":"山东巨野农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007713"},{"bank_alias":"江西兴国农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007716"},{"bank_alias":"青海格尔木农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007717"},{"bank_alias":"赣州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007718"},{"bank_alias":"绿春县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007720"},{"bank_alias":"彰武县冯家农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007726"},{"bank_alias":"宁洱哈尼族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007728"},{"bank_alias":"昆明市东川区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007729"},{"bank_alias":"东营农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007731"},{"bank_alias":"永仁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007736"},{"bank_alias":"兴隆县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007739"},{"bank_alias":"湖北荆州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007740"},{"bank_alias":"青海海晏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007743"},{"bank_alias":"湖北三峡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007745"},{"bank_alias":"兰坪县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007747"},{"bank_alias":"泸水市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007749"},{"bank_alias":"黑龙江省肇东市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007753"},{"bank_alias":"江西宜黄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007755"},{"bank_alias":"菏泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007757"},{"bank_alias":"建昌县喇嘛洞农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007758"},{"bank_alias":"梨树县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007759"},{"bank_alias":"井研县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007760"},{"bank_alias":"云南嵩明农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007762"},{"bank_alias":"湖北崇阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007763"},{"bank_alias":"民丰县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007765"},{"bank_alias":"乡城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007766"},{"bank_alias":"福建省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007768"},{"bank_alias":"湖北仙桃农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007770"},{"bank_alias":"福海县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007774"},{"bank_alias":"湖北通山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007776"},{"bank_alias":"青海大通农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007780"},{"bank_alias":"新疆伊犁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007781"},{"bank_alias":"绥化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007783"},{"bank_alias":"湖北监利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007784"},{"bank_alias":"湖北南漳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007787"},{"bank_alias":"齐齐哈尔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007791"},{"bank_alias":"肇东市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007793"},{"bank_alias":"山东荣成农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007794"},{"bank_alias":"赞皇县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007795"},{"bank_alias":"长顺县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007797"},{"bank_alias":"湖北郧县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007798"},{"bank_alias":"红河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007800"},{"bank_alias":"哈尔滨市呼兰区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007802"},{"bank_alias":"扶余市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007804"},{"bank_alias":"云南马关农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007807"},{"bank_alias":"云南华宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007809"},{"bank_alias":"青海门源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007811"},{"bank_alias":"山东莒县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007812"},{"bank_alias":"山东莱州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007813"},{"bank_alias":"乐亭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007814"},{"bank_alias":"山东沂水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007815"},{"bank_alias":"宁夏石嘴山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007816"},{"bank_alias":"阜平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007818"},{"bank_alias":"山东省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007822"},{"bank_alias":"绥中县高岭农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007823"},{"bank_alias":"山东栖霞农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007825"},{"bank_alias":"金平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007830"},{"bank_alias":"宝兴县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007831"},{"bank_alias":"云南元谋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007832"},{"bank_alias":"白玉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007833"},{"bank_alias":"穆棱市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007835"},{"bank_alias":"黑龙江省鹤岗市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007836"},{"bank_alias":"易门县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007838"},{"bank_alias":"山东蓬莱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007839"},{"bank_alias":"北镇市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007840"},{"bank_alias":"澜沧拉祜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007841"},{"bank_alias":"江西弋阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007842"},{"bank_alias":"江西庐陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007845"},{"bank_alias":"宜春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007846"},{"bank_alias":"黑龙江克东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007847"},{"bank_alias":"涞源县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007850"},{"bank_alias":"桦川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007851"},{"bank_alias":"新疆库尔勒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007854"},{"bank_alias":"若羌县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007856"},{"bank_alias":"成安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007857"},{"bank_alias":"湖北大冶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007859"},{"bank_alias":"本溪市市区平山农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007860"},{"bank_alias":"云南洱源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007863"},{"bank_alias":"湖北松滋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007864"},{"bank_alias":"山东商河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007866"},{"bank_alias":"江西进贤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007868"},{"bank_alias":"黑龙江鸡西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007870"},{"bank_alias":"保亭黎族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007873"},{"bank_alias":"湖北武当山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007878"},{"bank_alias":"尚志市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007879"},{"bank_alias":"耿马傣族佤族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007880"},{"bank_alias":"黑龙江讷河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007883"},{"bank_alias":"陵水黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007887"},{"bank_alias":"华坪县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007891"},{"bank_alias":"湖北通城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007893"},{"bank_alias":"桦南县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007898"},{"bank_alias":"华宁县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007899"},{"bank_alias":"通山楚农商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007900"},{"bank_alias":"山东单县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007905"},{"bank_alias":"昆明官渡农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007906"},{"bank_alias":"湖北咸丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007909"},{"bank_alias":"湖北省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007911"},{"bank_alias":"东莞农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007915"},{"bank_alias":"台安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007916"},{"bank_alias":"壤塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007918"},{"bank_alias":"南宫市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007919"},{"bank_alias":"日照东港农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007920"},{"bank_alias":"山东青州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007923"},{"bank_alias":"定兴县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007926"},{"bank_alias":"青海共和农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007927"},{"bank_alias":"巩留县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007928"},{"bank_alias":"雄县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007929"},{"bank_alias":"新疆阜康农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007930"},{"bank_alias":"新疆喀什农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007934"},{"bank_alias":"调兵山市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007936"},{"bank_alias":"抚顺县农村信用社合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007937"},{"bank_alias":"江西宜丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007939"},{"bank_alias":"金川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007940"},{"bank_alias":"湖北麻城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007942"},{"bank_alias":"山东茌平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007947"},{"bank_alias":"昌黎县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007949"},{"bank_alias":"湖北黄冈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007953"},{"bank_alias":"青龙满族自治县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007955"},{"bank_alias":"青海省农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007956"},{"bank_alias":"江西东乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007958"},{"bank_alias":"松原市宁江区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007959"},{"bank_alias":"南昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007960"},{"bank_alias":"岳普湖县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007963"},{"bank_alias":"江西横峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007964"},{"bank_alias":"湖北利川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007965"},{"bank_alias":"青海刚察农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007969"},{"bank_alias":"朝阳县柳城农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007970"},{"bank_alias":"哈巴河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007973"},{"bank_alias":"茂县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007977"},{"bank_alias":"山西省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007978"},{"bank_alias":"湖北阳新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007982"},{"bank_alias":"山东文登农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007983"},{"bank_alias":"潍坊市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007985"},{"bank_alias":"托克逊县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007988"},{"bank_alias":"皮山县科克铁热克乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007990"},{"bank_alias":"嘉荫县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007991"},{"bank_alias":"双鸭山市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007992"},{"bank_alias":"江西上犹农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007995"},{"bank_alias":"大关县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007997"},{"bank_alias":"三亚农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007998"},{"bank_alias":"建昌县八家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000007999"},{"bank_alias":"南江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008000"},{"bank_alias":"宁夏吴忠农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008001"},{"bank_alias":"江西赣昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008003"},{"bank_alias":"荥经县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008004"},{"bank_alias":"沿河土家族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008005"},{"bank_alias":"黑龙江省桦川县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008006"},{"bank_alias":"皮山县藏桂乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008008"},{"bank_alias":"铁力市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008013"},{"bank_alias":"山东高密农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008014"},{"bank_alias":"额敏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008015"},{"bank_alias":"张家口市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008016"},{"bank_alias":"勃利县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008017"},{"bank_alias":"麦盖提县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008019"},{"bank_alias":"马尔康县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008022"},{"bank_alias":"海南万宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008023"},{"bank_alias":"山东广饶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008024"},{"bank_alias":"望奎县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008025"},{"bank_alias":"青海贵德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008027"},{"bank_alias":"德江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008030"},{"bank_alias":"平泉市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008031"},{"bank_alias":"朝阳市双塔区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008032"},{"bank_alias":"佳木斯市郊区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008034"},{"bank_alias":"宁夏石嘴山市惠农区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008036"},{"bank_alias":"无极县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008039"},{"bank_alias":"法库县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008040"},{"bank_alias":"旺苍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008041"},{"bank_alias":"石阡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008042"},{"bank_alias":"青海湟中农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008044"},{"bank_alias":"景谷傣族彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008045"},{"bank_alias":"盘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008046"},{"bank_alias":"汉源县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008049"},{"bank_alias":"云南云县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008050"},{"bank_alias":"阜新县十家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008051"},{"bank_alias":"西宁农商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008052"},{"bank_alias":"铁岭县新台子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008055"},{"bank_alias":"水城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008058"},{"bank_alias":"云南凤庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008059"},{"bank_alias":"黑龙江庆安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008061"},{"bank_alias":"蔚县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008062"},{"bank_alias":"黑龙江省铁力市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008063"},{"bank_alias":"定安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008064"},{"bank_alias":"朝阳市龙城区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008065"},{"bank_alias":"山东梁山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008067"},{"bank_alias":"河北省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008072"},{"bank_alias":"叶城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008074"},{"bank_alias":"海南屯昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008077"},{"bank_alias":"江西鄱阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008079"},{"bank_alias":"个旧市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008080"},{"bank_alias":"皮山县克里阳乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008081"},{"bank_alias":"江西省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008082"},{"bank_alias":"夹江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008083"},{"bank_alias":"本溪市市区农村信用合作社联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008084"},{"bank_alias":"富宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008086"},{"bank_alias":"黑龙江省依安县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008089"},{"bank_alias":"山东东平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008091"},{"bank_alias":"青海乌兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008093"},{"bank_alias":"稻城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008095"},{"bank_alias":"黑龙江逊克农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008096"},{"bank_alias":"湖北远安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008097"},{"bank_alias":"岑巩县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008098"},{"bank_alias":"保定市满城区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008099"},{"bank_alias":"石渠县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008100"},{"bank_alias":"黑龙江孙吴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008101"},{"bank_alias":"山东临邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008102"},{"bank_alias":"青海湟源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008106"},{"bank_alias":"湖北团风农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008107"},{"bank_alias":"依兰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008108"},{"bank_alias":"云南陇川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008109"},{"bank_alias":"日照岚山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008111"},{"bank_alias":"湖北咸宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008113"},{"bank_alias":"泊头市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008114"},{"bank_alias":"墨玉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008118"},{"bank_alias":"巧家县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008120"},{"bank_alias":"和静县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008121"},{"bank_alias":"双辽市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008125"},{"bank_alias":"山东济阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008126"},{"bank_alias":"湖北宣恩农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008128"},{"bank_alias":"吉安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008133"},{"bank_alias":"鹰潭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008136"},{"bank_alias":"皮山县木奎拉乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008141"},{"bank_alias":"抚顺县上马农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008142"},{"bank_alias":"湖北嘉鱼农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008143"},{"bank_alias":"昆明晋宁区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008144"},{"bank_alias":"隆化县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008150"},{"bank_alias":"青海泽库农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008151"},{"bank_alias":"康平县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008152"},{"bank_alias":"伽师县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008153"},{"bank_alias":"本溪市市区通达农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008155"},{"bank_alias":"朝阳县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008156"},{"bank_alias":"富民县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008160"},{"bank_alias":"沈阳市苏家屯区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008161"},{"bank_alias":"黑龙江嫩江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008162"},{"bank_alias":"湖北鹤峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008165"},{"bank_alias":"宁夏平罗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008166"},{"bank_alias":"湖北枣阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008167"},{"bank_alias":"山东临沭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008168"},{"bank_alias":"山东鱼台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008169"},{"bank_alias":"新疆乌什农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008170"},{"bank_alias":"宁夏彭阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008174"},{"bank_alias":"天全县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008178"},{"bank_alias":"青海化隆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008181"},{"bank_alias":"尚义县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008183"},{"bank_alias":"山东曲阜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008185"},{"bank_alias":"吐鲁番市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008186"},{"bank_alias":"湖北郧西农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008187"},{"bank_alias":"江西瑞昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008188"},{"bank_alias":"台安县高力房农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008191"},{"bank_alias":"开江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008195"},{"bank_alias":"大城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008199"},{"bank_alias":"锦屏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008200"},{"bank_alias":"贡山独龙族怒族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008205"},{"bank_alias":"理县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008206"},{"bank_alias":"湖北大悟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008208"},{"bank_alias":"喀左县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008209"},{"bank_alias":"盘山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008210"},{"bank_alias":"墨江哈尼族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008212"},{"bank_alias":"曲阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008213"},{"bank_alias":"泽普县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008214"},{"bank_alias":"西丰县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008216"},{"bank_alias":"依安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008217"},{"bank_alias":"皮山县阔什塔格乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008218"},{"bank_alias":"淄博淄川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008219"},{"bank_alias":"永年县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008222"},{"bank_alias":"黑龙江建三江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008224"},{"bank_alias":"抚顺县石文农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008228"},{"bank_alias":"青冈县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008229"},{"bank_alias":"山东张店农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008230"},{"bank_alias":"德州陵城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008231"},{"bank_alias":"滨州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008233"},{"bank_alias":"新疆沙雅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008234"},{"bank_alias":"云南勐腊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008235"},{"bank_alias":"东方市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008239"},{"bank_alias":"泸定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008241"},{"bank_alias":"黑龙江同江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008242"},{"bank_alias":"黑龙江饶河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008244"},{"bank_alias":"新疆富蕴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008245"},{"bank_alias":"深泽县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008249"},{"bank_alias":"江西新建农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008250"},{"bank_alias":"黑龙江省佳木斯市郊区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008251"},{"bank_alias":"新疆木垒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008252"},{"bank_alias":"海伦市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008254"},{"bank_alias":"江西德兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008257"},{"bank_alias":"山东昌邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008259"},{"bank_alias":"云南龙陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008260"},{"bank_alias":"黑龙江省海林市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008262"},{"bank_alias":"江西上栗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008264"},{"bank_alias":"六枝特区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008265"},{"bank_alias":"山东乳山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008266"},{"bank_alias":"青海尖扎农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008267"},{"bank_alias":"云南陆良农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008270"},{"bank_alias":"黑龙江汤原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008272"},{"bank_alias":"大兴安岭农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008273"},{"bank_alias":"台安县城郊农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008275"},{"bank_alias":"福贡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008277"},{"bank_alias":"本溪市卧龙农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008278"},{"bank_alias":"黑龙江密山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008281"},{"bank_alias":"江西吉水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008282"},{"bank_alias":"湖北当阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008283"},{"bank_alias":"抚州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008286"},{"bank_alias":"磁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008289"},{"bank_alias":"湖北沙洋农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008290"},{"bank_alias":"西盟县农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008292"},{"bank_alias":"青海循化农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008293"},{"bank_alias":"和田市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008294"},{"bank_alias":"山东鄄城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008295"},{"bank_alias":"镇沅彝族哈尼族拉祜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008297"},{"bank_alias":"绵阳市涪城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008298"},{"bank_alias":"云南新平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008301"},{"bank_alias":"琼中黎族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008304"},{"bank_alias":"漾濞彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008305"},{"bank_alias":"山东阳谷农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008309"},{"bank_alias":"黑龙江北安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008310"},{"bank_alias":"山东招远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008311"},{"bank_alias":"吴桥县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008312"},{"bank_alias":"黑龙江省富锦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008318"},{"bank_alias":"北票市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008320"},{"bank_alias":"山东费县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008321"},{"bank_alias":"黑龙江塔河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008322"},{"bank_alias":"湖北广水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008323"},{"bank_alias":"昆明市盘龙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008324"},{"bank_alias":"新疆塔城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008325"},{"bank_alias":"江西彭泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008331"},{"bank_alias":"本溪市石桥子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008332"},{"bank_alias":"石家庄市藁城农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008334"},{"bank_alias":"峨边彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008335"},{"bank_alias":"松桃苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008336"},{"bank_alias":"湖北保康农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008338"},{"bank_alias":"朝阳市龙城区西大营子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008344"},{"bank_alias":"新疆伊宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008346"},{"bank_alias":"策勒县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008347"},{"bank_alias":"塔什库尔干县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008349"},{"bank_alias":"山东汶上农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008351"},{"bank_alias":"赤城县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008355"},{"bank_alias":"台安县台安镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008356"},{"bank_alias":"山东东阿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008357"},{"bank_alias":"芦山县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008358"},{"bank_alias":"云南永平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008360"},{"bank_alias":"西丰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008361"},{"bank_alias":"东辽县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008362"},{"bank_alias":"山东临沂罗庄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008367"},{"bank_alias":"海南临高农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008369"},{"bank_alias":"正安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008372"},{"bank_alias":"荣县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008373"},{"bank_alias":"山东金乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008374"},{"bank_alias":"石家庄市矿区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008376"},{"bank_alias":"黑龙江省青冈县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008378"},{"bank_alias":"泸州市纳溪区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008379"},{"bank_alias":"蓬溪县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008381"},{"bank_alias":"长岭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008383"},{"bank_alias":"绥江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008384"},{"bank_alias":"于田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008386"},{"bank_alias":"上饶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008390"},{"bank_alias":"本溪市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008391"},{"bank_alias":"枣庄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008393"},{"bank_alias":"建昌县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008396"},{"bank_alias":"施秉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008401"},{"bank_alias":"江西遂川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008402"},{"bank_alias":"湖北长阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008406"},{"bank_alias":"铁岭市清河区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008407"},{"bank_alias":"山东五莲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008408"},{"bank_alias":"洪雅县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008409"},{"bank_alias":"江西峡江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008410"},{"bank_alias":"湖北秭归农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008411"},{"bank_alias":"江西安义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008412"},{"bank_alias":"凌海市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008413"},{"bank_alias":"吉木乃县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008417"},{"bank_alias":"新疆昭苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008418"},{"bank_alias":"巴里坤哈萨克自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008419"},{"bank_alias":"淄博博山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008420"},{"bank_alias":"江西玉山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008422"},{"bank_alias":"精河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008423"},{"bank_alias":"湖北宜都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008424"},{"bank_alias":"五指山市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008426"},{"bank_alias":"青铜峡市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008429"},{"bank_alias":"湖北罗田农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008430"},{"bank_alias":"遵化市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008432"},{"bank_alias":"嘉荫县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008433"},{"bank_alias":"萍乡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008435"},{"bank_alias":"江西万安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008442"},{"bank_alias":"山东新泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008444"},{"bank_alias":"云南大理市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008446"},{"bank_alias":"黑龙江集贤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008447"},{"bank_alias":"江西修水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008448"},{"bank_alias":"镇康县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008449"},{"bank_alias":"宁夏同心农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008450"},{"bank_alias":"山东武城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008451"},{"bank_alias":"黑龙江萝北农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008454"},{"bank_alias":"江西安远农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008456"},{"bank_alias":"祥云县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008460"},{"bank_alias":"绥中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008462"},{"bank_alias":"永善县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008464"},{"bank_alias":"丽江古城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008467"},{"bank_alias":"黑龙江克山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008470"},{"bank_alias":"新疆呼图壁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008472"},{"bank_alias":"乐山三江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008476"},{"bank_alias":"云南南华农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008477"},{"bank_alias":"湖北老河口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008480"},{"bank_alias":"东光县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008481"},{"bank_alias":"黑龙江省穆棱市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008482"},{"bank_alias":"顺平县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008483"},{"bank_alias":"凌源市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008484"},{"bank_alias":"皮山县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008485"},{"bank_alias":"山东东明农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008486"},{"bank_alias":"皮山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008489"},{"bank_alias":"贵州省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008491"},{"bank_alias":"青海天峻农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008494"},{"bank_alias":"河间市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008496"},{"bank_alias":"江西南城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008497"},{"bank_alias":"山东平邑农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008498"},{"bank_alias":"北川羌族自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008501"},{"bank_alias":"山东诸城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008504"},{"bank_alias":"山东滕州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008506"},{"bank_alias":"赤水市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008508"},{"bank_alias":"台江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008511"},{"bank_alias":"辽宁省喀喇沁左翼蒙古族自治县公营子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008512"},{"bank_alias":"云南腾冲农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008513"},{"bank_alias":"云南永胜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008516"},{"bank_alias":"永宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008517"},{"bank_alias":"新疆阿克苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008518"},{"bank_alias":"阿坝州农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008519"},{"bank_alias":"武汉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008520"},{"bank_alias":"安新县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008521"},{"bank_alias":"铁岭县平顶堡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008523"},{"bank_alias":"鹤岗市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008525"},{"bank_alias":"江西崇仁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008527"},{"bank_alias":"新河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008529"},{"bank_alias":"江西崇义农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008530"},{"bank_alias":"新疆尉犁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008531"},{"bank_alias":"九龙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008533"},{"bank_alias":"皮山县皮亚勒玛乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008535"},{"bank_alias":"湖北随州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008538"},{"bank_alias":"山东定陶农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008541"},{"bank_alias":"山东郯城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008542"},{"bank_alias":"伊通满族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008543"},{"bank_alias":"辽中县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008544"},{"bank_alias":"容城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008547"},{"bank_alias":"山东龙口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008549"},{"bank_alias":"金沙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008551"},{"bank_alias":"抚顺县章党农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008552"},{"bank_alias":"山东安丘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008553"},{"bank_alias":"青海柴达木农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008554"},{"bank_alias":"曲靖市麒麟区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008560"},{"bank_alias":"黑龙江方正农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008561"},{"bank_alias":"特克斯县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008562"},{"bank_alias":"云南寻甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008564"},{"bank_alias":"泸县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008567"},{"bank_alias":"松潘县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008568"},{"bank_alias":"新疆石河子农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008570"},{"bank_alias":"黑龙江宾州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008571"},{"bank_alias":"云南普洱思茅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008573"},{"bank_alias":"石林彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008577"},{"bank_alias":"湖北竹溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008579"},{"bank_alias":"绥阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008580"},{"bank_alias":"山东成武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008584"},{"bank_alias":"武定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008588"},{"bank_alias":"鲁甸县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008591"},{"bank_alias":"黑龙江省兰西县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008593"},{"bank_alias":"石嘴山市惠农区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008596"},{"bank_alias":"无极县城关农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008597"},{"bank_alias":"黑龙江富裕农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008598"},{"bank_alias":"武邑县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008604"},{"bank_alias":"湖北黄梅农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008606"},{"bank_alias":"本溪市市区东兴农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008608"},{"bank_alias":"黑龙江省海伦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008609"},{"bank_alias":"湖北丹江口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008613"},{"bank_alias":"岳池县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008616"},{"bank_alias":"四川省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008617"},{"bank_alias":"山东寿光农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008627"},{"bank_alias":"山东庆云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008629"},{"bank_alias":"阿图什市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008630"},{"bank_alias":"德钦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008631"},{"bank_alias":"青河县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008632"},{"bank_alias":"黑龙江省林口县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008633"},{"bank_alias":"彰武县哈尔套农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008634"},{"bank_alias":"小金县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008636"},{"bank_alias":"大庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008637"},{"bank_alias":"义县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008638"},{"bank_alias":"巴楚县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008639"},{"bank_alias":"通江县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008640"},{"bank_alias":"山东惠民农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008641"},{"bank_alias":"海南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008643"},{"bank_alias":"双江拉祜族佤族布朗族傣族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008645"},{"bank_alias":"湖北京山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008646"},{"bank_alias":"黑龙江漠河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008647"},{"bank_alias":"华安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008648"},{"bank_alias":"黑龙江省嘉荫县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008649"},{"bank_alias":"铁岭市银州区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008650"},{"bank_alias":"甘孜州农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008655"},{"bank_alias":"洛浦县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008657"},{"bank_alias":"昆明市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008658"},{"bank_alias":"且末县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008659"},{"bank_alias":"肥乡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008661"},{"bank_alias":"朝阳市龙城区七道泉子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008663"},{"bank_alias":"宁夏贺兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008664"},{"bank_alias":"江西会昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008669"},{"bank_alias":"云南巍山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008670"},{"bank_alias":"铁岭县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008671"},{"bank_alias":"青海互助农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008673"},{"bank_alias":"云南鹤庆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008677"},{"bank_alias":"策勒县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008678"},{"bank_alias":"魏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008682"},{"bank_alias":"宁夏西吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008685"},{"bank_alias":"昆明市西山区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008686"},{"bank_alias":"新乐市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008689"},{"bank_alias":"惠安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008690"},{"bank_alias":"新疆乌苏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008693"},{"bank_alias":"沧源佤族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008698"},{"bank_alias":"富锦市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008699"},{"bank_alias":"云南隆阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008700"},{"bank_alias":"黑龙江鸡东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008701"},{"bank_alias":"云南临沧临翔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008706"},{"bank_alias":"七台河市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008707"},{"bank_alias":"凌源市城关镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008709"},{"bank_alias":"山东莒南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008710"},{"bank_alias":"新和县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008714"},{"bank_alias":"阿克陶县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008718"},{"bank_alias":"黄石农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008722"},{"bank_alias":"黑龙江绥棱农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008724"},{"bank_alias":"黑龙江甘南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008726"},{"bank_alias":"新疆乌鲁木齐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008729"},{"bank_alias":"石屏县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008733"},{"bank_alias":"山东临朐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008734"},{"bank_alias":"青县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008738"},{"bank_alias":"新疆博湖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008742"},{"bank_alias":"山东临沂河东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008743"},{"bank_alias":"湖北兴山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008745"},{"bank_alias":"湖北安陆农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008747"},{"bank_alias":"江苏省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008748"},{"bank_alias":"山东博兴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008749"},{"bank_alias":"蓬安县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008751"},{"bank_alias":"黑龙江东宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008752"},{"bank_alias":"青海都兰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008754"},{"bank_alias":"绥中县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008755"},{"bank_alias":"兰西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008756"},{"bank_alias":"平乡县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008757"},{"bank_alias":"山东垦利农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008758"},{"bank_alias":"江西永修农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008759"},{"bank_alias":"唐县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008762"},{"bank_alias":"青海贵南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008764"},{"bank_alias":"隆尧县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008766"},{"bank_alias":"喀左县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008769"},{"bank_alias":"邯郸市峰峰矿区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008771"},{"bank_alias":"云南蒙自农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008773"},{"bank_alias":"长白朝鲜族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008774"},{"bank_alias":"牡丹江市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008780"},{"bank_alias":"黑龙江省桦南县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008784"},{"bank_alias":"江西武宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008785"},{"bank_alias":"威县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008786"},{"bank_alias":"铁岭县凡河农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008788"},{"bank_alias":"江西都昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008789"},{"bank_alias":"黑龙江省牡丹江市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008792"},{"bank_alias":"聊城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008793"},{"bank_alias":"临漳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008794"},{"bank_alias":"湖北蕲春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008795"},{"bank_alias":"青海同德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008796"},{"bank_alias":"江油市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008797"},{"bank_alias":"台安县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008799"},{"bank_alias":"湖北赤壁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008806"},{"bank_alias":"罗甸县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008807"},{"bank_alias":"牟定县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008808"},{"bank_alias":"黑山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008811"},{"bank_alias":"和布克赛尔县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008813"},{"bank_alias":"山东蒙阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008814"},{"bank_alias":"巴里坤哈萨克自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008815"},{"bank_alias":"勐腊县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008817"},{"bank_alias":"宁夏海原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008818"},{"bank_alias":"昆明市晋宁区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008820"},{"bank_alias":"故城县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008821"},{"bank_alias":"山东桓台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008822"},{"bank_alias":"镇雄县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008823"},{"bank_alias":"昌图县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008824"},{"bank_alias":"四平市城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008826"},{"bank_alias":"湖北孝昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008828"},{"bank_alias":"和田市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008830"},{"bank_alias":"江西广丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008831"},{"bank_alias":"湖北钟祥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008832"},{"bank_alias":"温泉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008833"},{"bank_alias":"阿图什市农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008837"},{"bank_alias":"青岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008838"},{"bank_alias":"黑龙江省宁安市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008840"},{"bank_alias":"黑水县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008841"},{"bank_alias":"怀安县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008842"},{"bank_alias":"山东昌乐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008843"},{"bank_alias":"托里县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008844"},{"bank_alias":"木兰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008846"},{"bank_alias":"拜城县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008847"},{"bank_alias":"吉林省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008849"},{"bank_alias":"龙江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008851"},{"bank_alias":"山东曹县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008852"},{"bank_alias":"开远市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008853"},{"bank_alias":"江川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008854"},{"bank_alias":"江西莲花农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008857"},{"bank_alias":"哈尔滨市依兰县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008858"},{"bank_alias":"江西石城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008860"},{"bank_alias":"平昌县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008862"},{"bank_alias":"山东郓城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008864"},{"bank_alias":"江西于都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008865"},{"bank_alias":"云南弥渡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008866"},{"bank_alias":"江西乐安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008867"},{"bank_alias":"湖北潜江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008870"},{"bank_alias":"印江土家族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008872"},{"bank_alias":"黑龙江虎林农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008874"},{"bank_alias":"山东肥城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008878"},{"bank_alias":"共青农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008881"},{"bank_alias":"孟村回族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008885"},{"bank_alias":"桦南县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008889"},{"bank_alias":"湖北天门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008890"},{"bank_alias":"彰武县后新秋农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008892"},{"bank_alias":"北票市五间房农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008895"},{"bank_alias":"剑川县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008897"},{"bank_alias":"乐东黎族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008903"},{"bank_alias":"理塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008905"},{"bank_alias":"瑞丽市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008906"},{"bank_alias":"儋州市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008907"},{"bank_alias":"黑龙江省勃利县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008908"},{"bank_alias":"阜新蒙古族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008909"},{"bank_alias":"山东夏津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008910"},{"bank_alias":"江西上高农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008918"},{"bank_alias":"肃宁县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008919"},{"bank_alias":"伊春农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008921"},{"bank_alias":"江西龙南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008925"},{"bank_alias":"本溪市市区富佳农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008929"},{"bank_alias":"江西靖安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008932"},{"bank_alias":"乐山市金口河区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008936"},{"bank_alias":"洮南市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008939"},{"bank_alias":"阜蒙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008940"},{"bank_alias":"色达县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008942"},{"bank_alias":"昆明市呈贡区农村信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008945"},{"bank_alias":"湖北竹山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008946"},{"bank_alias":"宁夏固原农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008947"},{"bank_alias":"黑龙江肇州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008948"},{"bank_alias":"开原市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008952"},{"bank_alias":"雅江县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008955"},{"bank_alias":"宁夏盐池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008956"},{"bank_alias":"江西瑞金农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008958"},{"bank_alias":"乐山市五通桥区农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008962"},{"bank_alias":"元江哈尼族彝族傣族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008963"},{"bank_alias":"任丘市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008966"},{"bank_alias":"屏边县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008967"},{"bank_alias":"宁夏永宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008969"},{"bank_alias":"安宁市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008973"},{"bank_alias":"新疆温宿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008974"},{"bank_alias":"江西定南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008979"},{"bank_alias":"黑龙江肇源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008980"},{"bank_alias":"湖北谷城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008982"},{"bank_alias":"黑龙江五大连池农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008985"},{"bank_alias":"哈尔滨市阿城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008986"},{"bank_alias":"炉霍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008989"},{"bank_alias":"永德县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008990"},{"bank_alias":"新疆奇台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008992"},{"bank_alias":"云南盈江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008994"},{"bank_alias":"黑龙江五常农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008995"},{"bank_alias":"云南水富农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008996"},{"bank_alias":"雷山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008997"},{"bank_alias":"黑龙江明水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000008998"},{"bank_alias":"湖南省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009000"},{"bank_alias":"潍坊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009006"},{"bank_alias":"宁夏中卫农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009008"},{"bank_alias":"行唐县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009009"},{"bank_alias":"辽宁省北票市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009010"},{"bank_alias":"望都县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009012"},{"bank_alias":"云南弥勒农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009013"},{"bank_alias":"黑龙江林甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009015"},{"bank_alias":"云南禄丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009016"},{"bank_alias":"青冈县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009017"},{"bank_alias":"黑龙江宝清农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009019"},{"bank_alias":"裕民县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009021"},{"bank_alias":"江西永丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009022"},{"bank_alias":"抚顺县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009023"},{"bank_alias":"和硕县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009024"},{"bank_alias":"德格县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009026"},{"bank_alias":"双鸭山市市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009029"},{"bank_alias":"江西宁都农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009030"},{"bank_alias":"疏勒县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009031"},{"bank_alias":"林口县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009032"},{"bank_alias":"九寨沟县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009033"},{"bank_alias":"青海果洛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009035"},{"bank_alias":"道孚县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009036"},{"bank_alias":"黑龙江安达农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009037"},{"bank_alias":"湖北来凤农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009039"},{"bank_alias":"湖北十堰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009041"},{"bank_alias":"和布克赛尔蒙古自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009044"},{"bank_alias":"师宗县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009045"},{"bank_alias":"新疆霍城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009047"},{"bank_alias":"江西江州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009048"},{"bank_alias":"新疆沙湾农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009050"},{"bank_alias":"本溪市市区东风农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009052"},{"bank_alias":"秦皇岛市区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009053"},{"bank_alias":"朝阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009054"},{"bank_alias":"湖北浠水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009055"},{"bank_alias":"云南文山市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009059"},{"bank_alias":"青海玉树农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009060"},{"bank_alias":"丹巴县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009063"},{"bank_alias":"湖北洪湖农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009064"},{"bank_alias":"海南澄迈农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009067"},{"bank_alias":"三河市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009068"},{"bank_alias":"拜泉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009069"},{"bank_alias":"云南施甸农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009071"},{"bank_alias":"山东周村农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009072"},{"bank_alias":"鹤岗市市区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009073"},{"bank_alias":"江西资溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009074"},{"bank_alias":"湖北宜城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009078"},{"bank_alias":"威宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009079"},{"bank_alias":"湖北襄阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009083"},{"bank_alias":"松桃苗族自治县信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009085"},{"bank_alias":"博野县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009086"},{"bank_alias":"新疆轮台农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009088"},{"bank_alias":"云南建水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009090"},{"bank_alias":"望奎县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009091"},{"bank_alias":"盐亭县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009093"},{"bank_alias":"江西万载农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009094"},{"bank_alias":"湖北五峰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009095"},{"bank_alias":"山东宁津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009099"},{"bank_alias":"将乐县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009101"},{"bank_alias":"山东高青农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009105"},{"bank_alias":"山东章丘农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009106"},{"bank_alias":"佳木斯市郊区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009109"},{"bank_alias":"山东威海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009110"},{"bank_alias":"山东莘县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009111"},{"bank_alias":"邱北县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009114"},{"bank_alias":"景德镇农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009116"},{"bank_alias":"云南玉龙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009124"},{"bank_alias":"迁西县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009129"},{"bank_alias":"云南威信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009130"},{"bank_alias":"梅河口市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009131"},{"bank_alias":"青海兴海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009134"},{"bank_alias":"禄劝彝族苗族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009137"},{"bank_alias":"云南会泽农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009139"},{"bank_alias":"西畴县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009140"},{"bank_alias":"泰安泰山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009141"},{"bank_alias":"绵阳市游仙区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009142"},{"bank_alias":"纳雍县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009143"},{"bank_alias":"南涧彝族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009145"},{"bank_alias":"黑龙江友谊农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009146"},{"bank_alias":"辽宁省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009148"},{"bank_alias":"江西湖口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009149"},{"bank_alias":"廊坊市城郊农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009150"},{"bank_alias":"铁力市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009152"},{"bank_alias":"哈尔滨市呼兰区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009154"},{"bank_alias":"台安县西佛农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009155"},{"bank_alias":"江西安福农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009156"},{"bank_alias":"江西大余农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009158"},{"bank_alias":"新疆博乐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009159"},{"bank_alias":"山东济宁兖州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009164"},{"bank_alias":"朝阳市龙城区沈承农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009166"},{"bank_alias":"云南芒市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009168"},{"bank_alias":"和田县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009169"},{"bank_alias":"西丰县西丰镇农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009172"},{"bank_alias":"若尔盖县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009173"},{"bank_alias":"湖北石首农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009174"},{"bank_alias":"江西新干农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009176"},{"bank_alias":"曲周县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009177"},{"bank_alias":"双城市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009181"},{"bank_alias":"保定市徐水区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009185"},{"bank_alias":"山东聊城润昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009186"},{"bank_alias":"云南楚雄市农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009188"},{"bank_alias":"彰武县东六家子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009189"},{"bank_alias":"沧县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009190"},{"bank_alias":"海口市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009191"},{"bank_alias":"江西婺源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009192"},{"bank_alias":"山东沂源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009193"},{"bank_alias":"山东利津农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009195"},{"bank_alias":"富源县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009196"},{"bank_alias":"湖北武穴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009198"},{"bank_alias":"黑河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009199"},{"bank_alias":"彰武县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009200"},{"bank_alias":"大田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009202"},{"bank_alias":"江西余干农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009203"},{"bank_alias":"山东莱阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009204"},{"bank_alias":"和田县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009206"},{"bank_alias":"湖北红安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009211"},{"bank_alias":"沐川县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009213"},{"bank_alias":"新疆昌吉农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009214"},{"bank_alias":"山东微山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009216"},{"bank_alias":"维西傈僳族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009224"},{"bank_alias":"山东临淄农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009227"},{"bank_alias":"青海河南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009228"},{"bank_alias":"山东齐河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009229"},{"bank_alias":"新疆吉木萨尔农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009235"},{"bank_alias":"山东莱州农村农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009236"},{"bank_alias":"云南景洪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009240"},{"bank_alias":"新疆天山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009242"},{"bank_alias":"海兴县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009243"},{"bank_alias":"黑龙江通河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009245"},{"bank_alias":"新疆维吾尔自治区农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009248"},{"bank_alias":"莎车县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009249"},{"bank_alias":"山东兰陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009250"},{"bank_alias":"乾安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009251"},{"bank_alias":"云南彝良农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009252"},{"bank_alias":"江西寻乌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009253"},{"bank_alias":"江西南丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009255"},{"bank_alias":"湖北房县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009256"},{"bank_alias":"巴彦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009257"},{"bank_alias":"抚顺县救兵农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009259"},{"bank_alias":"江西永新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009260"},{"bank_alias":"乐山市沙湾区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009262"},{"bank_alias":"巴塘县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009265"},{"bank_alias":"海伦市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009266"},{"bank_alias":"江西湾里农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009267"},{"bank_alias":"阿克陶县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009268"},{"bank_alias":"山东平阴农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009269"},{"bank_alias":"湖北枝江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009271"},{"bank_alias":"湖北云梦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009274"},{"bank_alias":"香格里拉县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009275"},{"bank_alias":"江西铜鼓农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009280"},{"bank_alias":"石棉县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009281"},{"bank_alias":"宁夏灵武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009282"},{"bank_alias":"湖北公安农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009284"},{"bank_alias":"易县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009286"},{"bank_alias":"邯郸市城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009287"},{"bank_alias":"调兵山市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009289"},{"bank_alias":"肇东市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009291"},{"bank_alias":"山东嘉祥农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009292"},{"bank_alias":"开阳县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009293"},{"bank_alias":"承德市郊区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009294"},{"bank_alias":"云南景东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009296"},{"bank_alias":"江西信丰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009297"},{"bank_alias":"湖北建始农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009300"},{"bank_alias":"湖北荆门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009301"},{"bank_alias":"江口县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009302"},{"bank_alias":"凌源市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009303"},{"bank_alias":"云南祥云农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009304"},{"bank_alias":"江西金溪农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009305"},{"bank_alias":"黑龙江绥滨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009307"},{"bank_alias":"平坝县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009309"},{"bank_alias":"山东阳信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009312"},{"bank_alias":"焉耆回族自治县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009314"},{"bank_alias":"抚顺市顺城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009315"},{"bank_alias":"库车县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009323"},{"bank_alias":"云南通海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009324"},{"bank_alias":"山东海阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009325"},{"bank_alias":"江西全南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009326"},{"bank_alias":"本溪市北台农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009327"},{"bank_alias":"伊吾县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009328"},{"bank_alias":"山东长岛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009329"},{"bank_alias":"新疆北屯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009332"},{"bank_alias":"甘孜县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009333"},{"bank_alias":"宁夏泾源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009336"},{"bank_alias":"姚安县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009340"},{"bank_alias":"青海祁连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009342"},{"bank_alias":"皮山县农场农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009344"},{"bank_alias":"云南河口农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009345"},{"bank_alias":"新余农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009351"},{"bank_alias":"朝阳市龙城区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009352"},{"bank_alias":"江西丰城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009353"},{"bank_alias":"山东沂南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009355"},{"bank_alias":"玉溪市江川区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009356"},{"bank_alias":"湖北英山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009358"},{"bank_alias":"皮山县木吉乡农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009359"},{"bank_alias":"洛浦县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009362"},{"bank_alias":"广东省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009366"},{"bank_alias":"黑龙江绥芬河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009367"},{"bank_alias":"马边彝族自治县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009370"},{"bank_alias":"山东邹城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009376"},{"bank_alias":"黑龙江杜尔伯特农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009378"},{"bank_alias":"湖北神农架农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009380"},{"bank_alias":"江西奉新农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009381"},{"bank_alias":"邱县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009382"},{"bank_alias":"彰武县农村信用合作联四合城信用社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009383"},{"bank_alias":"云南易门农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009386"},{"bank_alias":"江西广信农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009388"},{"bank_alias":"北票市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009389"},{"bank_alias":"新疆阿勒泰农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009393"},{"bank_alias":"绥中县万家农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009394"},{"bank_alias":"英吉沙县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009398"},{"bank_alias":"山东邹平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009404"},{"bank_alias":"泰安岱岳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009407"},{"bank_alias":"康保县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009409"},{"bank_alias":"湖北江陵农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009412"},{"bank_alias":"青海西宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009414"},{"bank_alias":"本溪市高台子农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009416"},{"bank_alias":"建昌县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009417"},{"bank_alias":"饶阳县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009418"},{"bank_alias":"红原县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009419"},{"bank_alias":"兰西县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009420"},{"bank_alias":"盐津县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009422"},{"bank_alias":"济宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009423"},{"bank_alias":"石家庄市矿区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009427"},{"bank_alias":"武安市农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009430"},{"bank_alias":"云南广南农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009431"},{"bank_alias":"昆明市呈贡区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009432"},{"bank_alias":"山东临沂兰山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009436"},{"bank_alias":"山东泗水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009439"},{"bank_alias":"黑龙江延寿农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009440"},{"bank_alias":"琼海市农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009441"},{"bank_alias":"高邑县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009442"},{"bank_alias":"海南文昌农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009443"},{"bank_alias":"黑龙江呼玛农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009444"},{"bank_alias":"石家庄市栾城农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009445"},{"bank_alias":"墨玉县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009446"},{"bank_alias":"云南宁蒗农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009448"},{"bank_alias":"黑龙江省龙江县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009449"},{"bank_alias":"本溪市市区牛心台农村信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009455"},{"bank_alias":"九江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009458"},{"bank_alias":"云南昌宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009459"},{"bank_alias":"湖北巴东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009466"},{"bank_alias":"建宁县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009471"},{"bank_alias":"云南罗平农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009473"},{"bank_alias":"阿坝县农村信用合作社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009475"},{"bank_alias":"高阳县农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009477"},{"bank_alias":"江西铅山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009479"},{"bank_alias":"山东高唐农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009482"},{"bank_alias":"乌恰县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009483"},{"bank_alias":"湖北汉川农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009484"},{"bank_alias":"保定市清苑区农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009485"},{"bank_alias":"海南白沙农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009490"},{"bank_alias":"石家庄汇融农村合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009491"},{"bank_alias":"江苏苏宁银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009493"},{"bank_alias":"温州民商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009494"},{"bank_alias":"深圳前海微众银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009495"},{"bank_alias":"重庆富民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009496"},{"bank_alias":"福建华通银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009499"},{"bank_alias":"无锡锡商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009500"},{"bank_alias":"浙江网商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009501"},{"bank_alias":"江西裕民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009502"},{"bank_alias":"武汉众邦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009504"},{"bank_alias":"天津金城银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009506"},{"bank_alias":"辽宁振兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009507"},{"bank_alias":"上海华瑞银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009508"},{"bank_alias":"四川新网银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009510"},{"bank_alias":"梅州客商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009511"},{"bank_alias":"营口经济技术开发区熊岳城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009512"},{"bank_alias":"盖州市城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009513"},{"bank_alias":"盖州市城市建设信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009514"},{"bank_alias":"盖州市辰州城市信用合作社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009515"},{"bank_alias":"大西洋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009516"},{"bank_alias":"印度尼西亚曼底利银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009517"},{"bank_alias":"台湾中小企业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009518"},{"bank_alias":"西班牙对外银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009519"},{"bank_alias":"巴基斯坦哈比银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009520"},{"bank_alias":"澳门国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009521"},{"bank_alias":"泰国汇商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009522"},{"bank_alias":"大丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009523"},{"bank_alias":"澳大利亚澳洲联邦银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009524"},{"bank_alias":"韩国大邱银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009525"},{"bank_alias":"荷兰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009526"},{"bank_alias":"日本名古屋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009527"},{"bank_alias":"韩国釜山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009528"},{"bank_alias":"永丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009529"},{"bank_alias":"马来西亚联昌银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009530"},{"bank_alias":"中国信托商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009531"},{"bank_alias":"浦发硅谷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009532"},{"bank_alias":"埃及国民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009533"},{"bank_alias":"盘锦农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009534"},{"bank_alias":"长治市上党区泰都村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009536"},{"bank_alias":"晋中市太谷兴泰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009537"},{"bank_alias":"黑龙江省农村信用社联合社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009542"},{"bank_alias":"安顺市平坝区农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009544"},{"bank_alias":"云南澄江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009545"},{"bank_alias":"新疆布尔津喀纳斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009546"},{"bank_alias":"恒丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009564"},{"bank_alias":"浙商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009565"},{"bank_alias":"渤海银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009566"},{"bank_alias":"重庆三峡银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009567"},{"bank_alias":"上海农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009568"},{"bank_alias":"汇丰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009572"},{"bank_alias":"东亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009573"},{"bank_alias":"恒生银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009575"},{"bank_alias":"集友银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009576"},{"bank_alias":"创兴银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009577"},{"bank_alias":"大众银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009578"},{"bank_alias":"上海商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009579"},{"bank_alias":"招商永隆银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009580"},{"bank_alias":"大新银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009581"},{"bank_alias":"华南商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009582"},{"bank_alias":"彰银商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009583"},{"bank_alias":"国泰世华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009584"},{"bank_alias":"合作金库商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009585"},{"bank_alias":"第一商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009586"},{"bank_alias":"台湾土地银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009587"},{"bank_alias":"兆丰国际商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009588"},{"bank_alias":"台湾银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009589"},{"bank_alias":"玉山银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009590"},{"bank_alias":"美国银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009592"},{"bank_alias":"美国建东银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009594"},{"bank_alias":"印度国家银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009595"},{"bank_alias":"三菱日联银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009596"},{"bank_alias":"三井住友银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009597"},{"bank_alias":"瑞穗银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009598"},{"bank_alias":"日本山口银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009599"},{"bank_alias":"日本三井住友信托银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009600"},{"bank_alias":"日本横滨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009601"},{"bank_alias":"友利银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009602"},{"bank_alias":"韩国产业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009603"},{"bank_alias":"新韩银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009604"},{"bank_alias":"韩亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009606"},{"bank_alias":"国民银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009607"},{"bank_alias":"马来西亚马来亚银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009608"},{"bank_alias":"首都银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009609"},{"bank_alias":"华侨永亨银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009610"},{"bank_alias":"大华银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009611"},{"bank_alias":"盘谷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009613"},{"bank_alias":"泰国泰京银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009614"},{"bank_alias":"开泰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009615"},{"bank_alias":"奥地利奥合国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009616"},{"bank_alias":"比利时联合银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009617"},{"bank_alias":"荷兰安智银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009618"},{"bank_alias":"英国巴克莱银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009620"},{"bank_alias":"瑞典北欧斯安银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009622"},{"bank_alias":"瑞典银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009623"},{"bank_alias":"法国兴业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009624"},{"bank_alias":"法国外贸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009626"},{"bank_alias":"德意志银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009627"},{"bank_alias":"德国商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009628"},{"bank_alias":"德国北德意志州银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009629"},{"bank_alias":"中德住房储蓄银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009630"},{"bank_alias":"意大利裕信银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009631"},{"bank_alias":"意大利联合圣保罗银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009632"},{"bank_alias":"瑞士信贷银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009633"},{"bank_alias":"瑞士银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009634"},{"bank_alias":"加拿大丰业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009635"},{"bank_alias":"蒙特利尔银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009636"},{"bank_alias":"澳大利亚和新西兰银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009637"},{"bank_alias":"澳大利亚西太平洋银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009638"},{"bank_alias":"西班牙桑坦德银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009639"},{"bank_alias":"俄罗斯外贸银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009640"},{"bank_alias":"摩根士丹利国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009641"},{"bank_alias":"华美银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009642"},{"bank_alias":"荷兰合作银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009643"},{"bank_alias":"厦门国际银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009644"},{"bank_alias":"华商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009646"},{"bank_alias":"富邦华一银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009647"},{"bank_alias":"网联清算有限公司","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009648"},{"bank_alias":"挪威银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009649"},{"bank_alias":"新联商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009650"},{"bank_alias":"徽商银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009667"},{"bank_alias":"北京昌平发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009669"},{"bank_alias":"达尔罕茂明安联合旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009670"},{"bank_alias":"鄂温克蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009671"},{"bank_alias":"福建松溪长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009672"},{"bank_alias":"福建永泰长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009674"},{"bank_alias":"甘孜农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009675"},{"bank_alias":"固阳蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009676"},{"bank_alias":"广元市发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009684"},{"bank_alias":"贵州册亨农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009685"},{"bank_alias":"贵州剑河农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009686"},{"bank_alias":"贵州望谟农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009687"},{"bank_alias":"湖北荆门掇刀德通村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009690"},{"bank_alias":"湖南绥宁湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009691"},{"bank_alias":"化德蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009692"},{"bank_alias":"江苏丹阳苏银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009693"},{"bank_alias":"江西万载富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009694"},{"bank_alias":"鄄城牡丹村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009695"},{"bank_alias":"芦山县农村信用合作联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009696"},{"bank_alias":"漯河市郾城发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009697"},{"bank_alias":"莫力达瓦蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009699"},{"bank_alias":"南通如皋润泽村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009701"},{"bank_alias":"内蒙古和林格尔蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009703"},{"bank_alias":"宁城蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009705"},{"bank_alias":"宁夏红寺堡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009706"},{"bank_alias":"宁夏隆德农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009707"},{"bank_alias":"祁东惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009708"},{"bank_alias":"秦皇岛市抚宁农村信用联社","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009709"},{"bank_alias":"陕西榆林农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009717"},{"bank_alias":"四川江油农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009719"},{"bank_alias":"四川旺苍农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009720"},{"bank_alias":"四川银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009721"},{"bank_alias":"乌兰察布市集宁蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009722"},{"bank_alias":"乌审旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009723"},{"bank_alias":"武冈发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009724"},{"bank_alias":"西平中原村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009725"},{"bank_alias":"西乌珠穆沁蒙商惠丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009726"},{"bank_alias":"息烽发展村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009727"},{"bank_alias":"新疆阿瓦提农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009728"},{"bank_alias":"新疆玛纳斯农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009729"},{"bank_alias":"新疆鄯善农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009730"},{"bank_alias":"兴安盟科尔沁蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009731"},{"bank_alias":"兴和蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009732"},{"bank_alias":"扬州仪征玉丰村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009734"},{"bank_alias":"云南麻栗坡农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009735"},{"bank_alias":"云南双柏农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009736"},{"bank_alias":"云南砚山农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009737"},{"bank_alias":"准格尔旗蒙商村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009738"},{"bank_alias":"贵州习水农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009739"},{"bank_alias":"山西蒲县农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009740"},{"bank_alias":"浙江永康农银村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009741"},{"bank_alias":"云南孟连农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009742"},{"bank_alias":"万年稻源村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009743"},{"bank_alias":"广西武宣农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009744"},{"bank_alias":"福建华安长信村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009745"},{"bank_alias":"福建邵武农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009746"},{"bank_alias":"浙江东阳富富民村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009747"},{"bank_alias":"湖南江永湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009748"},{"bank_alias":"辽沈银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009749"},{"bank_alias":"万宁金谷村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009750"},{"bank_alias":"广西宾阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009751"},{"bank_alias":"湖南新田湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009752"},{"bank_alias":"新疆新源农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009753"},{"bank_alias":"福建连江农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009754"},{"bank_alias":"湖南炎陵星龙村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009755"},{"bank_alias":"青海海东农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009756"},{"bank_alias":"山西霍州农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009757"},{"bank_alias":"贵州镇宁农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009758"},{"bank_alias":"重庆开州泰业村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009759"},{"bank_alias":"宁波甬城农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009760"},{"bank_alias":"云南元阳农村商业银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009762"},{"bank_alias":"湖南桑植湘农村镇银行","need_bank_branch":true,"account_bank":"其他银行","account_bank_code":1099,"bank_alias_code":"1000009763"},{"bank_alias":"杭州银行","need_bank_branch":false,"account_bank":"杭州银行","account_bank_code":1109,"bank_alias_code":"1000005307"},{"bank_alias":"无锡农村商业银行","need_bank_branch":false,"account_bank":"无锡农商行","account_bank_code":4031,"bank_alias_code":"1000007493"},{"bank_alias":"献县融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000005360"},{"bank_alias":"广东普宁汇成村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000005847"},{"bank_alias":"东营融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006028"},{"bank_alias":"遵化融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006089"},{"bank_alias":"汕头潮阳融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006134"},{"bank_alias":"龙川融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006229"},{"bank_alias":"饶平融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006296"},{"bank_alias":"广州黄埔融和村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006929"},{"bank_alias":"广东澄海潮商村镇银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006934"},{"bank_alias":"广东吴川农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006951"},{"bank_alias":"广东连平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006952"},{"bank_alias":"广东翁源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006954"},{"bank_alias":"广东连山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006955"},{"bank_alias":"广东连州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006959"},{"bank_alias":"广东始兴农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006961"},{"bank_alias":"广东平远农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006965"},{"bank_alias":"珠海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006972"},{"bank_alias":"广东阳山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006976"},{"bank_alias":"广东兴宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000006981"},{"bank_alias":"广东丰顺农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007005"},{"bank_alias":"广东化州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007012"},{"bank_alias":"广东佛冈农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007033"},{"bank_alias":"广东阳春农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007035"},{"bank_alias":"广东鹤山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007039"},{"bank_alias":"广东揭阳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007040"},{"bank_alias":"广东乐昌农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007054"},{"bank_alias":"广东揭东农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007059"},{"bank_alias":"广东徐闻农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007074"},{"bank_alias":"广东龙门农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007079"},{"bank_alias":"广东广宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007082"},{"bank_alias":"广东高州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007106"},{"bank_alias":"广东封开农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007113"},{"bank_alias":"广东信宜农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007116"},{"bank_alias":"广东新丰农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007126"},{"bank_alias":"广东遂溪农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007131"},{"bank_alias":"广东东源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007132"},{"bank_alias":"广东博罗农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007149"},{"bank_alias":"广东蕉岭农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007159"},{"bank_alias":"广东南澳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007202"},{"bank_alias":"广东英德农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007204"},{"bank_alias":"佛山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007229"},{"bank_alias":"广东清新农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007255"},{"bank_alias":"广东南海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007257"},{"bank_alias":"广东普宁农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007258"},{"bank_alias":"广东乳源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007265"},{"bank_alias":"广东陆河农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007277"},{"bank_alias":"广东和平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007278"},{"bank_alias":"广东大埔农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007297"},{"bank_alias":"广东惠东农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007301"},{"bank_alias":"广东河源农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007304"},{"bank_alias":"惠州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007312"},{"bank_alias":"广东南雄农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007314"},{"bank_alias":"广东紫金农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007326"},{"bank_alias":"韶关农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007331"},{"bank_alias":"广东仁化农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007345"},{"bank_alias":"广东揭西农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007348"},{"bank_alias":"广东德庆农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007349"},{"bank_alias":"广东廉江农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007363"},{"bank_alias":"湛江农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007367"},{"bank_alias":"广东开平农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007386"},{"bank_alias":"广东陆丰农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007392"},{"bank_alias":"广东阳西农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007404"},{"bank_alias":"中山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007405"},{"bank_alias":"广东新兴农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007408"},{"bank_alias":"广东龙川农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007411"},{"bank_alias":"江门农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007417"},{"bank_alias":"广东怀集农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007424"},{"bank_alias":"梅州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007444"},{"bank_alias":"广东五华农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007449"},{"bank_alias":"广东四会农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007461"},{"bank_alias":"广东罗定农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007464"},{"bank_alias":"广东清远农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007466"},{"bank_alias":"广东台山农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007468"},{"bank_alias":"广东连南农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007473"},{"bank_alias":"肇庆农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007490"},{"bank_alias":"广东茂名农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007495"},{"bank_alias":"汕尾农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007506"},{"bank_alias":"广东雷州农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000007513"},{"bank_alias":"广东云浮农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009535"},{"bank_alias":"广东潮阳农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009677"},{"bank_alias":"广东澄海农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009678"},{"bank_alias":"广东惠来农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009679"},{"bank_alias":"广东郁南农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009680"},{"bank_alias":"汕头海湾农村商业银行","need_bank_branch":false,"account_bank":"广东农信","account_bank_code":4035,"bank_alias_code":"1000009718"},{"bank_alias":"广东顺德农村商业银行","need_bank_branch":false,"account_bank":"顺德农商银行","account_bank_code":4036,"bank_alias_code":"1000007068"},{"bank_alias":"浙江泰隆商业银行","need_bank_branch":false,"account_bank":"浙江泰隆商业银行","account_bank_code":4051,"bank_alias_code":"1000005310"},{"bank_alias":"宁波鄞州农村商业银行","need_bank_branch":false,"account_bank":"宁波鄞州农村商业银行","account_bank_code":4052,"bank_alias_code":"1000009163"},{"bank_alias":"邵武刺桐红村镇银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000005703"},{"bank_alias":"寿宁刺桐红村镇银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000006187"},{"bank_alias":"福建三明农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007075"},{"bank_alias":"福建南平农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007263"},{"bank_alias":"泉州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007296"},{"bank_alias":"福建上杭农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007302"},{"bank_alias":"福建永安农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007400"},{"bank_alias":"福建漳州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007426"},{"bank_alias":"福建安溪农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007465"},{"bank_alias":"福建石狮农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007475"},{"bank_alias":"福建福州农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007479"},{"bank_alias":"福建莆田农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007502"},{"bank_alias":"柘荣县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007557"},{"bank_alias":"闽清县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007569"},{"bank_alias":"漳浦县农村信用社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007598"},{"bank_alias":"霞浦县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007666"},{"bank_alias":"长汀县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007719"},{"bank_alias":"泰宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007756"},{"bank_alias":"平和县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007769"},{"bank_alias":"永春县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007772"},{"bank_alias":"诏安县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007820"},{"bank_alias":"松溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007874"},{"bank_alias":"政和县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007907"},{"bank_alias":"仙游县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007938"},{"bank_alias":"连城县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007945"},{"bank_alias":"顺昌县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000007957"},{"bank_alias":"周宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008009"},{"bank_alias":"清流县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008132"},{"bank_alias":"邵武市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008139"},{"bank_alias":"长泰县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008184"},{"bank_alias":"福建长乐农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008237"},{"bank_alias":"福建南安农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008276"},{"bank_alias":"古田县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008315"},{"bank_alias":"安溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008328"},{"bank_alias":"德化县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008329"},{"bank_alias":"尤溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008359"},{"bank_alias":"福建漳平农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008385"},{"bank_alias":"东山县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008495"},{"bank_alias":"福建建瓯农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008557"},{"bank_alias":"南靖县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008594"},{"bank_alias":"龙岩市永定区农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008618"},{"bank_alias":"明溪县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008620"},{"bank_alias":"福鼎市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008626"},{"bank_alias":"寿宁县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008667"},{"bank_alias":"福建宁德农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008705"},{"bank_alias":"福建龙岩农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008750"},{"bank_alias":"罗源县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008761"},{"bank_alias":"屏南县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008768"},{"bank_alias":"永泰县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008855"},{"bank_alias":"福建武夷山农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008913"},{"bank_alias":"宁化县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008943"},{"bank_alias":"福安市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000008993"},{"bank_alias":"武平县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009018"},{"bank_alias":"闽侯县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009070"},{"bank_alias":"福建龙海农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009080"},{"bank_alias":"福建福清汇通农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009082"},{"bank_alias":"漳浦县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009103"},{"bank_alias":"永安市农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009120"},{"bank_alias":"南平市建阳区农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009232"},{"bank_alias":"云霄县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009272"},{"bank_alias":"厦门农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009322"},{"bank_alias":"光泽县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009373"},{"bank_alias":"福建晋江农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009374"},{"bank_alias":"福建沙县农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009375"},{"bank_alias":"连江县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009406"},{"bank_alias":"浦城县农村信用合作联社","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009481"},{"bank_alias":"福建平潭农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009489"},{"bank_alias":"福建仙游农村商业银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009673"},{"bank_alias":"南平农商银行","need_bank_branch":false,"account_bank":"福建农信","account_bank_code":4064,"bank_alias_code":"1000009700"},{"bank_alias":"江苏紫金农村商业银行","need_bank_branch":false,"account_bank":"江苏紫金农村商业银行","account_bank_code":4072,"bank_alias_code":"1000007083"},{"bank_alias":"江苏紫金农商行","need_bank_branch":false,"account_bank":"江苏紫金农村商业银行","account_bank_code":4072,"bank_alias_code":"1000007289"},{"bank_alias":"深圳农村商业银行","need_bank_branch":false,"account_bank":"深圳农村商业银行","account_bank_code":4076,"bank_alias_code":"1000008173"},{"bank_alias":"西安鄠邑农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007158"},{"bank_alias":"陕西周至农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007195"},{"bank_alias":"陕西蓝田农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007233"},{"bank_alias":"陕西秦农农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007240"},{"bank_alias":"黄陵县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007543"},{"bank_alias":"西安市长安区太乙宫农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007548"},{"bank_alias":"西安市长安区鸣犊农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007549"},{"bank_alias":"陕西旬阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007578"},{"bank_alias":"陕西靖边农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007580"},{"bank_alias":"陕西石泉农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007583"},{"bank_alias":"宜君县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007597"},{"bank_alias":"陕西岚皋农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007606"},{"bank_alias":"泾阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007629"},{"bank_alias":"洛南县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007632"},{"bank_alias":"陕西汉阴农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007659"},{"bank_alias":"铜川市印台区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007714"},{"bank_alias":"陕西洛川农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007737"},{"bank_alias":"蒲城县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007773"},{"bank_alias":"洋县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007824"},{"bank_alias":"陕西眉县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007844"},{"bank_alias":"陕西吴堡农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007871"},{"bank_alias":"渭南市临渭区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007876"},{"bank_alias":"陕西佳县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007884"},{"bank_alias":"陕西镇坪农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007894"},{"bank_alias":"城固县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007896"},{"bank_alias":"西安市长安区五台农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007904"},{"bank_alias":"略阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007914"},{"bank_alias":"陕西丹凤农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007925"},{"bank_alias":"陕西南郑农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007968"},{"bank_alias":"黄龙县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007971"},{"bank_alias":"陕西彬州农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007972"},{"bank_alias":"西安市长安区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007979"},{"bank_alias":"西安市长安区纪阳农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000007984"},{"bank_alias":"宝鸡市陈仓区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008021"},{"bank_alias":"延长县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008053"},{"bank_alias":"汉中市汉台区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008060"},{"bank_alias":"陕西岐山农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008088"},{"bank_alias":"富平县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008104"},{"bank_alias":"陕西清涧农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008105"},{"bank_alias":"西安市长安区内苑农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008115"},{"bank_alias":"华阴市农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008138"},{"bank_alias":"陕西子洲农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008157"},{"bank_alias":"陕西咸阳渭城农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008203"},{"bank_alias":"大荔县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008236"},{"bank_alias":"陕西宁陕农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008243"},{"bank_alias":"乾县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008246"},{"bank_alias":"陕西千阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008284"},{"bank_alias":"陕西吴起农村合作银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008285"},{"bank_alias":"陕西西乡农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008314"},{"bank_alias":"旬邑县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008319"},{"bank_alias":"西安市长安区杜陵农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008330"},{"bank_alias":"陕西山阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008350"},{"bank_alias":"宁强县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008380"},{"bank_alias":"兴平市农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008427"},{"bank_alias":"陕西镇安农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008439"},{"bank_alias":"陕西横山农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008441"},{"bank_alias":"西安市长安区王曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008457"},{"bank_alias":"西安市长安区细柳农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008492"},{"bank_alias":"陕西咸阳秦都农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008503"},{"bank_alias":"渭南市华州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008507"},{"bank_alias":"陕西府谷农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008545"},{"bank_alias":"铜川市耀州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008566"},{"bank_alias":"延安农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008569"},{"bank_alias":"陕西柞水农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008603"},{"bank_alias":"西安市长安区东大农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008622"},{"bank_alias":"陕西陇县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008684"},{"bank_alias":"礼泉县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008741"},{"bank_alias":"陕西绥德农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008767"},{"bank_alias":"合阳县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008775"},{"bank_alias":"延川县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008779"},{"bank_alias":"志丹县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008791"},{"bank_alias":"陕西平利农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008809"},{"bank_alias":"陕西神木农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008827"},{"bank_alias":"西安市长安区马王农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008845"},{"bank_alias":"陕西宝鸡金台农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008863"},{"bank_alias":"勉县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008868"},{"bank_alias":"陕西宝鸡渭滨农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008882"},{"bank_alias":"西安市长安区申店农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008888"},{"bank_alias":"西安市长安区滦镇农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008891"},{"bank_alias":"陕西商南农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008899"},{"bank_alias":"陕西麟游农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008900"},{"bank_alias":"陕西长武农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008911"},{"bank_alias":"陕西彬县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008914"},{"bank_alias":"三原县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008923"},{"bank_alias":"陕西甘泉农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008935"},{"bank_alias":"陕西韩城农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008977"},{"bank_alias":"陕西凤翔农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000008999"},{"bank_alias":"潼关县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009002"},{"bank_alias":"西安市长安区韦曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009003"},{"bank_alias":"西安市长安区引镇农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009011"},{"bank_alias":"扶风县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009034"},{"bank_alias":"陕西杨凌农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009066"},{"bank_alias":"陕西子长农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009127"},{"bank_alias":"西安市长安区郭杜农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009128"},{"bank_alias":"西安市长安区五星农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009144"},{"bank_alias":"永寿县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009180"},{"bank_alias":"西安市长安区王莽农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009194"},{"bank_alias":"陕西安塞农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009210"},{"bank_alias":"留坝县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009233"},{"bank_alias":"陕西凤县农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009237"},{"bank_alias":"陕西紫阳农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009241"},{"bank_alias":"陕西省农村信用社联合社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009246"},{"bank_alias":"白水县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009277"},{"bank_alias":"西安市长安区城区农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009278"},{"bank_alias":"商洛市商州区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009306"},{"bank_alias":"西安市长安区大兆农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009313"},{"bank_alias":"陕西镇巴农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009318"},{"bank_alias":"西安市长安区斗门农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009343"},{"bank_alias":"安康农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009346"},{"bank_alias":"陕西定边农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009385"},{"bank_alias":"陕西富县农村合作银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009392"},{"bank_alias":"铜川市王益区农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009410"},{"bank_alias":"武功县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009413"},{"bank_alias":"淳化县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009415"},{"bank_alias":"陕西白河农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009425"},{"bank_alias":"西安市长安区子午农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009437"},{"bank_alias":"宜川县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009438"},{"bank_alias":"陕西米脂农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009452"},{"bank_alias":"澄城县农村信用合作联社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009456"},{"bank_alias":"陕西太白农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009476"},{"bank_alias":"西安市长安区杜曲农村信用合作社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009486"},{"bank_alias":"西安市长安区农村信用合作社联合社","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009488"},{"bank_alias":"陕西佛坪农村商业银行","need_bank_branch":false,"account_bank":"陕西省农村信用社","account_bank_code":4108,"bank_alias_code":"1000009716"},{"bank_alias":"北京农村商业银行","need_bank_branch":false,"account_bank":"北京农村商业银行","account_bank_code":4112,"bank_alias_code":"1000008612"},{"bank_alias":"广西象州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007530"},{"bank_alias":"广西西林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007540"},{"bank_alias":"广西天等农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007551"},{"bank_alias":"广西资源农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007585"},{"bank_alias":"南宁市武鸣区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007592"},{"bank_alias":"广西临桂农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007594"},{"bank_alias":"广西扶绥农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007622"},{"bank_alias":"玉林市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007655"},{"bank_alias":"广西灵川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007667"},{"bank_alias":"博白县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007678"},{"bank_alias":"广西永福农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007699"},{"bank_alias":"防城港市防城区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007704"},{"bank_alias":"广西靖西农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007734"},{"bank_alias":"广西蒙山农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007754"},{"bank_alias":"广西田阳农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007801"},{"bank_alias":"梧州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007810"},{"bank_alias":"广西大新农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007827"},{"bank_alias":"广西壮族自治区农村信用社联合社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007834"},{"bank_alias":"广西凭祥农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007882"},{"bank_alias":"广西平果农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007897"},{"bank_alias":"广西宜州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007921"},{"bank_alias":"广西上林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007944"},{"bank_alias":"广西恭城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007946"},{"bank_alias":"广西龙州农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000007986"},{"bank_alias":"广西隆林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008007"},{"bank_alias":"广西田林农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008033"},{"bank_alias":"广西融安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008035"},{"bank_alias":"南宁市邕宁区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008037"},{"bank_alias":"广西东兴农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008073"},{"bank_alias":"天峨县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008075"},{"bank_alias":"广西凌云农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008090"},{"bank_alias":"大化瑶族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008094"},{"bank_alias":"广西龙胜农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008147"},{"bank_alias":"南丹县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008154"},{"bank_alias":"容县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008159"},{"bank_alias":"广西罗城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008172"},{"bank_alias":"广西巴马农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008211"},{"bank_alias":"北海市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008226"},{"bank_alias":"广西乐业农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008268"},{"bank_alias":"广西浦北农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008274"},{"bank_alias":"广西平乐农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008287"},{"bank_alias":"广西兴安农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008342"},{"bank_alias":"广西鹿寨农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008353"},{"bank_alias":"环江毛南族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008403"},{"bank_alias":"广西融水农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008437"},{"bank_alias":"藤县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008455"},{"bank_alias":"广西柳江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008466"},{"bank_alias":"广西灌阳农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008586"},{"bank_alias":"河池市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008614"},{"bank_alias":"广西那坡农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008624"},{"bank_alias":"合山市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008665"},{"bank_alias":"广西田东农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008672"},{"bank_alias":"凤山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008691"},{"bank_alias":"三江侗族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008697"},{"bank_alias":"广西百色右江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008711"},{"bank_alias":"兴业县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008717"},{"bank_alias":"广西荔浦农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008735"},{"bank_alias":"广西岑溪农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008781"},{"bank_alias":"广西马山农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008812"},{"bank_alias":"柳州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008834"},{"bank_alias":"广西阳朔农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008856"},{"bank_alias":"广西桂林漓江农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008884"},{"bank_alias":"桂平市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008898"},{"bank_alias":"忻城县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008924"},{"bank_alias":"灵山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008926"},{"bank_alias":"南宁市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008933"},{"bank_alias":"广西上思农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008934"},{"bank_alias":"广西陆川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008954"},{"bank_alias":"德保县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008959"},{"bank_alias":"广西全州农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008964"},{"bank_alias":"广西昭平农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000008983"},{"bank_alias":"广西柳城农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009112"},{"bank_alias":"防城港市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009115"},{"bank_alias":"广西贺州桂东农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009136"},{"bank_alias":"广西崇左桂南农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009187"},{"bank_alias":"东兰县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009209"},{"bank_alias":"广西富川农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009219"},{"bank_alias":"广西宁明农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009244"},{"bank_alias":"钟山县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009311"},{"bank_alias":"北流市农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009316"},{"bank_alias":"广西来宾桂中农村合作银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009363"},{"bank_alias":"横县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009391"},{"bank_alias":"广西隆安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009424"},{"bank_alias":"平南县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009428"},{"bank_alias":"钦州市区农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009434"},{"bank_alias":"合浦县农村信用合作联社","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009454"},{"bank_alias":"广西金秀农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009543"},{"bank_alias":"广西苍梧农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009681"},{"bank_alias":"广西都安农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009682"},{"bank_alias":"广西贵港荷城农村商业银行","need_bank_branch":false,"account_bank":"广西壮族自治区农村信用社","account_bank_code":4113,"bank_alias_code":"1000009683"},{"bank_alias":"三门峡陕州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007528"},{"bank_alias":"河南林州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007536"},{"bank_alias":"河南南乐农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007584"},{"bank_alias":"河南杞县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007626"},{"bank_alias":"河南尉氏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007644"},{"bank_alias":"河南内乡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007645"},{"bank_alias":"河南邓州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007650"},{"bank_alias":"南阳市宛城区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007668"},{"bank_alias":"河南中牟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007677"},{"bank_alias":"郸城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007693"},{"bank_alias":"郑州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007709"},{"bank_alias":"平顶山市石龙区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007710"},{"bank_alias":"驻马店农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007746"},{"bank_alias":"河南汤阴农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007748"},{"bank_alias":"河南淮滨农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007767"},{"bank_alias":"河南汝南农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007786"},{"bank_alias":"河南长垣农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007848"},{"bank_alias":"河南汝阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007853"},{"bank_alias":"河南西峡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007869"},{"bank_alias":"河南平舆农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007892"},{"bank_alias":"洛阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007902"},{"bank_alias":"许昌农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007917"},{"bank_alias":"河南永城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007931"},{"bank_alias":"河南襄城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007943"},{"bank_alias":"河南新郑农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000007987"},{"bank_alias":"河南博爱农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008010"},{"bank_alias":"河南叶县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008026"},{"bank_alias":"信阳市浉河区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008028"},{"bank_alias":"舞阳县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008057"},{"bank_alias":"河南民权农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008071"},{"bank_alias":"河南渑池农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008078"},{"bank_alias":"虞城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008103"},{"bank_alias":"河南桐柏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008116"},{"bank_alias":"睢县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008145"},{"bank_alias":"信阳市平桥区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008149"},{"bank_alias":"南阳市卧龙区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008158"},{"bank_alias":"临颍县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008163"},{"bank_alias":"新乡市凤泉区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008164"},{"bank_alias":"河南卢氏农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008177"},{"bank_alias":"河南宜阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008179"},{"bank_alias":"三门峡湖滨农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008180"},{"bank_alias":"温县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008204"},{"bank_alias":"河南延津农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008215"},{"bank_alias":"河南潢川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008225"},{"bank_alias":"河南镇平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008240"},{"bank_alias":"河南栾川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008261"},{"bank_alias":"淇县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008269"},{"bank_alias":"焦作市山阳区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008271"},{"bank_alias":"河南太康农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008280"},{"bank_alias":"河南安阳商都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008296"},{"bank_alias":"河南嵩县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008300"},{"bank_alias":"焦作市马村区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008307"},{"bank_alias":"河南许昌许都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008313"},{"bank_alias":"方城县农村信用合作社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008340"},{"bank_alias":"河南舞钢农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008397"},{"bank_alias":"河南息县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008405"},{"bank_alias":"禹州市农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008431"},{"bank_alias":"河南确山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008434"},{"bank_alias":"河南登封农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008440"},{"bank_alias":"商丘华商农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008463"},{"bank_alias":"河南获嘉农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008469"},{"bank_alias":"河南新密农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008471"},{"bank_alias":"河南安阳相州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008478"},{"bank_alias":"河南固始农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008502"},{"bank_alias":"河南范县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008510"},{"bank_alias":"河南罗山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008526"},{"bank_alias":"河南沈丘农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008536"},{"bank_alias":"河南淅川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008537"},{"bank_alias":"河南荥阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008565"},{"bank_alias":"河南孟州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008595"},{"bank_alias":"河南扶沟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008605"},{"bank_alias":"河南清丰农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008623"},{"bank_alias":"河南兰考农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008654"},{"bank_alias":"平顶山卫东农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008675"},{"bank_alias":"河南巩义农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008680"},{"bank_alias":"河南鄢陵农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008688"},{"bank_alias":"平顶山市新华区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008702"},{"bank_alias":"淮阳县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008704"},{"bank_alias":"河南滑县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008720"},{"bank_alias":"周口农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008725"},{"bank_alias":"河南省农村信用社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008727"},{"bank_alias":"内黄县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008746"},{"bank_alias":"河南浚县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008763"},{"bank_alias":"河南社旗农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008765"},{"bank_alias":"郏县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008770"},{"bank_alias":"鲁山县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008776"},{"bank_alias":"河南长葛农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008777"},{"bank_alias":"漯河市源汇区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008801"},{"bank_alias":"河南宝丰农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008825"},{"bank_alias":"鹤壁农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008835"},{"bank_alias":"河南偃师农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008861"},{"bank_alias":"河南沁阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008873"},{"bank_alias":"焦作市中站区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008876"},{"bank_alias":"河南鹿邑农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008894"},{"bank_alias":"河南泌阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008896"},{"bank_alias":"河南辉县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008902"},{"bank_alias":"河南新野农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008912"},{"bank_alias":"新乡县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008941"},{"bank_alias":"封丘县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008950"},{"bank_alias":"河南南召农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008953"},{"bank_alias":"河南上蔡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008961"},{"bank_alias":"河南原阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008968"},{"bank_alias":"河南孟津农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008970"},{"bank_alias":"河南台前农村商行银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000008976"},{"bank_alias":"河南商水农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009028"},{"bank_alias":"夏邑县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009046"},{"bank_alias":"河南新蔡农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009051"},{"bank_alias":"漯河市郾城区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009056"},{"bank_alias":"河南洛宁农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009075"},{"bank_alias":"河南义马农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009107"},{"bank_alias":"宁陵县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009108"},{"bank_alias":"河南新安农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009113"},{"bank_alias":"河南西平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009122"},{"bank_alias":"河南灵宝农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009133"},{"bank_alias":"平顶山市市郊农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009157"},{"bank_alias":"河南正阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009162"},{"bank_alias":"西华县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009167"},{"bank_alias":"河南汴京农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009207"},{"bank_alias":"焦作解放农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009230"},{"bank_alias":"河南修武农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009261"},{"bank_alias":"河南柘城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009299"},{"bank_alias":"河南济源农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009331"},{"bank_alias":"信阳市明港农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009335"},{"bank_alias":"河南汝州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009341"},{"bank_alias":"唐河县农村信用合作社联合社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009347"},{"bank_alias":"河南项城农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009350"},{"bank_alias":"濮阳农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009360"},{"bank_alias":"漯河市召陵区农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009364"},{"bank_alias":"商城县农村信用合作联社","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009384"},{"bank_alias":"河南伊川农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009390"},{"bank_alias":"河南新县农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009395"},{"bank_alias":"河南光山农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009396"},{"bank_alias":"河南通许农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009405"},{"bank_alias":"开封宋都农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009408"},{"bank_alias":"河南武陟农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009429"},{"bank_alias":"河南遂平农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009469"},{"bank_alias":"河南新乡平原农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009487"},{"bank_alias":"河南濮阳开州农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009688"},{"bank_alias":"河南卫辉农村商业银行","need_bank_branch":false,"account_bank":"河南省农村信用社","account_bank_code":4115,"bank_alias_code":"1000009689"},{"bank_alias":"宁夏黄河农村商业银行","need_bank_branch":false,"account_bank":"宁夏黄河农村商业银行","account_bank_code":4150,"bank_alias_code":"1000008716"},{"bank_alias":"天津农村商业银行","need_bank_branch":false,"account_bank":"天津农村商业银行","account_bank_code":4153,"bank_alias_code":"1000008524"},{"bank_alias":"晋中开发区农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007529"},{"bank_alias":"山西省交口县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007542"},{"bank_alias":"太原市小店区亲贤农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007552"},{"bank_alias":"山西省吕梁市文水县城关第二农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007556"},{"bank_alias":"山西省临县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007596"},{"bank_alias":"山西侯马农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007605"},{"bank_alias":"山西阳城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007609"},{"bank_alias":"太原市晋源区姚村农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007627"},{"bank_alias":"长治潞州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007651"},{"bank_alias":"山西平遥农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007652"},{"bank_alias":"大同县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007674"},{"bank_alias":"晋城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007680"},{"bank_alias":"石楼县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007681"},{"bank_alias":"山西垣曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007682"},{"bank_alias":"太原市小店区黄陵农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007721"},{"bank_alias":"山西壶关农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007732"},{"bank_alias":"山西古交农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007744"},{"bank_alias":"山西省吕梁市文水县凤城农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007764"},{"bank_alias":"山西榆次农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007771"},{"bank_alias":"文水县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007775"},{"bank_alias":"山西闻喜农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007778"},{"bank_alias":"山西芮城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007790"},{"bank_alias":"山西稷山农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007817"},{"bank_alias":"山西河津农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007828"},{"bank_alias":"山西山阴农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007858"},{"bank_alias":"山西孝义农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007872"},{"bank_alias":"山西省汾阳市三泉农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007910"},{"bank_alias":"山西左权农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007913"},{"bank_alias":"山西怀仁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007922"},{"bank_alias":"山西运城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007933"},{"bank_alias":"山西省石楼县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007941"},{"bank_alias":"山西洪洞农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007954"},{"bank_alias":"山西省吕梁市文水县城关第一农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007961"},{"bank_alias":"交口县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007976"},{"bank_alias":"山西省吕梁市中阳县金罗农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007989"},{"bank_alias":"山西省汾阳市冀村农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007994"},{"bank_alias":"山西沁水农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000007996"},{"bank_alias":"太原市万柏林区后王农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008018"},{"bank_alias":"太原市晋源区金胜农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008020"},{"bank_alias":"太原市晋源区晋祠农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008066"},{"bank_alias":"山西安泽农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008070"},{"bank_alias":"太原市城区农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008117"},{"bank_alias":"太原市迎泽区郝庄农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008122"},{"bank_alias":"太原市万柏林区西铭农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008124"},{"bank_alias":"翼城县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008131"},{"bank_alias":"山西尧都农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008140"},{"bank_alias":"太原市晋源区晋源农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008146"},{"bank_alias":"山西省汾阳市城关农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008192"},{"bank_alias":"山西原平农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008193"},{"bank_alias":"山西泽州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008196"},{"bank_alias":"长治漳泽农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008202"},{"bank_alias":"山西省吕梁市交口县双池农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008223"},{"bank_alias":"山西长治黎都农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008232"},{"bank_alias":"山西襄垣农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008256"},{"bank_alias":"汾阳市农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008263"},{"bank_alias":"山西省方山县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008288"},{"bank_alias":"太原市娄烦县农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008299"},{"bank_alias":"山西省汾阳市农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008308"},{"bank_alias":"山西昔阳农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008317"},{"bank_alias":"太原市杏花岭区杨家峪农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008339"},{"bank_alias":"山西省太原市城区农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008341"},{"bank_alias":"山西省汾阳市文峰农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008343"},{"bank_alias":"山西繁峙农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008348"},{"bank_alias":"太原市杏花岭区中涧河农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008363"},{"bank_alias":"山西夏县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008365"},{"bank_alias":"山西灵丘农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008366"},{"bank_alias":"山西五台农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008371"},{"bank_alias":"山西岚县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008382"},{"bank_alias":"山西右玉农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008388"},{"bank_alias":"山西沁源农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008389"},{"bank_alias":"山西宁武农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008394"},{"bank_alias":"太原市小店区刘家堡农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008395"},{"bank_alias":"山西忻州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008425"},{"bank_alias":"山西高平农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008436"},{"bank_alias":"山西万荣农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008445"},{"bank_alias":"山西永和农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008452"},{"bank_alias":"山西省娄烦县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008465"},{"bank_alias":"山西永济农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008499"},{"bank_alias":"陵川县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008505"},{"bank_alias":"山西襄汾农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008515"},{"bank_alias":"山西省阳高县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008546"},{"bank_alias":"山西省吕梁市中阳县城关农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008550"},{"bank_alias":"太原市尖草坪区柴村农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008556"},{"bank_alias":"太原市小店区西温庄农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008558"},{"bank_alias":"山西浮山农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008574"},{"bank_alias":"山西省运城市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008575"},{"bank_alias":"山西省汾阳市阳城农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008587"},{"bank_alias":"山西省应县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008592"},{"bank_alias":"山西曲沃农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008607"},{"bank_alias":"中阳县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008621"},{"bank_alias":"山西岢岚农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008644"},{"bank_alias":"山西屯留农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008652"},{"bank_alias":"山西省广灵县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008694"},{"bank_alias":"山西省大同县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008708"},{"bank_alias":"山西乡宁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008713"},{"bank_alias":"太原市尖草坪区向阳农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008730"},{"bank_alias":"山西静乐农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008739"},{"bank_alias":"太原市小店区小店农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008753"},{"bank_alias":"太原市尖草坪区新城农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008782"},{"bank_alias":"山西和顺农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008787"},{"bank_alias":"太原市万柏林区东社农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008802"},{"bank_alias":"阳泉农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008848"},{"bank_alias":"山西柳林农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008869"},{"bank_alias":"山西大宁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008877"},{"bank_alias":"山西省吕梁市中阳县枝柯农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008879"},{"bank_alias":"山西武乡农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008883"},{"bank_alias":"山西兴县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008886"},{"bank_alias":"山西阳曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008893"},{"bank_alias":"山西平顺农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008930"},{"bank_alias":"山西绛县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008960"},{"bank_alias":"天镇县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008971"},{"bank_alias":"山西太谷农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008975"},{"bank_alias":"山西灵石农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000008988"},{"bank_alias":"山西榆社农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009001"},{"bank_alias":"代县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009027"},{"bank_alias":"山西省汾阳市城西农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009043"},{"bank_alias":"山西省忻州市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009057"},{"bank_alias":"山西寿阳农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009058"},{"bank_alias":"朔州农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009076"},{"bank_alias":"山西左云农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009084"},{"bank_alias":"山西清徐农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009087"},{"bank_alias":"山西潞城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009102"},{"bank_alias":"山西长子农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009118"},{"bank_alias":"山西省吕梁市文水县孝义农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009179"},{"bank_alias":"吕梁市农村信用合作社联合社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009197"},{"bank_alias":"太原市尖草坪区阳曲农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009212"},{"bank_alias":"山西盂县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009215"},{"bank_alias":"山西黎城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009218"},{"bank_alias":"山西省晋城市陵川县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009225"},{"bank_alias":"太原市万柏林区小井峪农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009226"},{"bank_alias":"太原市小店区朝阳农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009231"},{"bank_alias":"太原市小店区北格农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009270"},{"bank_alias":"山西省天镇县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009273"},{"bank_alias":"山西省朔州市应县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009308"},{"bank_alias":"山西介休农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009317"},{"bank_alias":"山西平陆农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009320"},{"bank_alias":"方山县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009321"},{"bank_alias":"山西沁县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009337"},{"bank_alias":"山西五寨农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009361"},{"bank_alias":"山西临猗农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009371"},{"bank_alias":"山西河曲农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009387"},{"bank_alias":"山西交城农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009402"},{"bank_alias":"山西省吕梁市文水县开栅农村信用社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009411"},{"bank_alias":"山西神池农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009426"},{"bank_alias":"山西省中阳县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009435"},{"bank_alias":"太原市万柏林区沙沟农村信用合作社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009453"},{"bank_alias":"临县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009460"},{"bank_alias":"山西省代县农村信用合作联社","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009468"},{"bank_alias":"大同农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009474"},{"bank_alias":"山西平定农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009538"},{"bank_alias":"山西定襄农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009539"},{"bank_alias":"山西古县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009540"},{"bank_alias":"山西隰县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009541"},{"bank_alias":"吕梁农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009698"},{"bank_alias":"山西保德农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009710"},{"bank_alias":"山西浑源农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009711"},{"bank_alias":"山西吉县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009712"},{"bank_alias":"山西偏关农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009713"},{"bank_alias":"山西祁县农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009714"},{"bank_alias":"山西新绛农村商业银行","need_bank_branch":false,"account_bank":"山西省农村信用社","account_bank_code":4156,"bank_alias_code":"1000009715"},{"bank_alias":"武威农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006956"},{"bank_alias":"甘肃陇西农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006969"},{"bank_alias":"甘肃敦煌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006994"},{"bank_alias":"甘肃华亭农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000006999"},{"bank_alias":"甘肃灵台农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007009"},{"bank_alias":"兰州农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007025"},{"bank_alias":"金昌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007030"},{"bank_alias":"甘肃玉门农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007072"},{"bank_alias":"平凉农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007088"},{"bank_alias":"甘肃静宁农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007111"},{"bank_alias":"甘肃民乐农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007114"},{"bank_alias":"甘肃礼县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007115"},{"bank_alias":"甘肃高台农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007136"},{"bank_alias":"甘肃古浪农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007162"},{"bank_alias":"甘肃临洮农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007166"},{"bank_alias":"甘肃泾川农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007178"},{"bank_alias":"酒泉农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007185"},{"bank_alias":"张掖农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007192"},{"bank_alias":"嘉峪关农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007199"},{"bank_alias":"甘肃西和农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007215"},{"bank_alias":"甘肃两当农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007234"},{"bank_alias":"甘肃会宁农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007260"},{"bank_alias":"甘肃秦安农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007280"},{"bank_alias":"甘肃康县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007320"},{"bank_alias":"甘肃天祝农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007337"},{"bank_alias":"庆阳农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007340"},{"bank_alias":"甘肃永昌农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007342"},{"bank_alias":"甘肃山丹农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007360"},{"bank_alias":"甘肃靖远农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007368"},{"bank_alias":"临夏农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007381"},{"bank_alias":"甘肃瓜州农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007382"},{"bank_alias":"甘肃庄浪农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007391"},{"bank_alias":"甘肃崇信农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007403"},{"bank_alias":"定西农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007429"},{"bank_alias":"甘肃岷县农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007501"},{"bank_alias":"甘肃临泽农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007514"},{"bank_alias":"甘肃民勤农村商业银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007518"},{"bank_alias":"玛曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007554"},{"bank_alias":"和政县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007560"},{"bank_alias":"甘谷县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007567"},{"bank_alias":"定西市通渭县鸡川信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007576"},{"bank_alias":"甘肃宁县农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007603"},{"bank_alias":"甘肃榆中农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007616"},{"bank_alias":"白银区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007619"},{"bank_alias":"甘肃省通渭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007654"},{"bank_alias":"皋兰县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007663"},{"bank_alias":"陇南武都农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007687"},{"bank_alias":"肃北蒙古族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007688"},{"bank_alias":"文县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007696"},{"bank_alias":"肃南裕固族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007733"},{"bank_alias":"天水秦州农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007738"},{"bank_alias":"通渭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007750"},{"bank_alias":"庆城县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007782"},{"bank_alias":"成县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007789"},{"bank_alias":"舟曲县城关农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007792"},{"bank_alias":"正宁县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007799"},{"bank_alias":"张家川回族自治县信用联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007805"},{"bank_alias":"徽县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007861"},{"bank_alias":"康乐县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007881"},{"bank_alias":"永靖县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007886"},{"bank_alias":"清水县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007901"},{"bank_alias":"白银市白银区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007948"},{"bank_alias":"张掖市肃南县皇城信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007950"},{"bank_alias":"卓尼县农村信用合作社联合社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007962"},{"bank_alias":"张家川回族自治县信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000007981"},{"bank_alias":"东乡族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008048"},{"bank_alias":"景泰县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008110"},{"bank_alias":"肃南县农村信用联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008134"},{"bank_alias":"夏河县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008135"},{"bank_alias":"碌曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008137"},{"bank_alias":"天水麦积农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008176"},{"bank_alias":"舟曲县立节农村信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008198"},{"bank_alias":"舟曲县城关信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008201"},{"bank_alias":"金塔县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008221"},{"bank_alias":"定西市通渭县常河信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008327"},{"bank_alias":"定西市通渭县陇山信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008352"},{"bank_alias":"定西市漳县新寺信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008364"},{"bank_alias":"永登县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008387"},{"bank_alias":"玛曲县农村信用合作社联合社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008416"},{"bank_alias":"张家川回族自治县联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008438"},{"bank_alias":"合水县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008548"},{"bank_alias":"积石山县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008555"},{"bank_alias":"漳县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008559"},{"bank_alias":"华池县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008578"},{"bank_alias":"永靖县盐锅峡农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008601"},{"bank_alias":"张家川回族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008615"},{"bank_alias":"镇原县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008628"},{"bank_alias":"白银市平川区农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008660"},{"bank_alias":"广河县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008662"},{"bank_alias":"甘肃省康乐县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008692"},{"bank_alias":"迭部县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008728"},{"bank_alias":"甘肃庄浪农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008732"},{"bank_alias":"宕昌县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008804"},{"bank_alias":"合作市农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008810"},{"bank_alias":"舟曲县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008829"},{"bank_alias":"临夏市农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008880"},{"bank_alias":"定西市通渭县义岗信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008887"},{"bank_alias":"临潭县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008901"},{"bank_alias":"卓尼县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008965"},{"bank_alias":"积石山保安族东乡族撒拉族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008984"},{"bank_alias":"定西市漳县三岔信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000008991"},{"bank_alias":"阿克塞哈萨克族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009014"},{"bank_alias":"武威市凉州区上泉农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009020"},{"bank_alias":"甘肃省渭源县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009062"},{"bank_alias":"天祝县藏族自治县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009081"},{"bank_alias":"环县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009092"},{"bank_alias":"武山县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009096"},{"bank_alias":"舟曲县插岗农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009147"},{"bank_alias":"定西市通渭县榜罗信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009184"},{"bank_alias":"甘肃陇西农村合作银行","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009208"},{"bank_alias":"定西市通渭县城关信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009285"},{"bank_alias":"临夏县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009338"},{"bank_alias":"渭源县农村信用合作联社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009339"},{"bank_alias":"广河县三甲集农村信用合作社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009433"},{"bank_alias":"武威市凉州区下双农村信用社","need_bank_branch":false,"account_bank":"甘肃省农村信用社","account_bank_code":4157,"bank_alias_code":"1000009465"},{"bank_alias":"内蒙古太仆寺农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007526"},{"bank_alias":"包头农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007541"},{"bank_alias":"内蒙古五原农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007564"},{"bank_alias":"额济纳旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007572"},{"bank_alias":"巴彦淖尔河套农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007582"},{"bank_alias":"阿巴嘎旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007588"},{"bank_alias":"内蒙古自治区农村信用社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007595"},{"bank_alias":"内蒙古宁城农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007610"},{"bank_alias":"乌兰浩特市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007637"},{"bank_alias":"巴林右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007639"},{"bank_alias":"赤峰元宝山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007647"},{"bank_alias":"凉城县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007695"},{"bank_alias":"察哈尔右翼后旗农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007702"},{"bank_alias":"内蒙古阿尔山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007707"},{"bank_alias":"内蒙古伊金霍洛农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007708"},{"bank_alias":"和林格尔县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007723"},{"bank_alias":"额尔古纳市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007725"},{"bank_alias":"开鲁县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007741"},{"bank_alias":"内蒙古克什克腾农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007752"},{"bank_alias":"扎兰屯市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007779"},{"bank_alias":"通辽市科尔沁区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007788"},{"bank_alias":"武川县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007803"},{"bank_alias":"内蒙古西乌珠穆沁农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007806"},{"bank_alias":"内蒙古陕坝农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007821"},{"bank_alias":"翁牛特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007849"},{"bank_alias":"察哈尔右翼中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007855"},{"bank_alias":"科尔沁右翼前旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007865"},{"bank_alias":"和林格尔农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007875"},{"bank_alias":"巴林左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007888"},{"bank_alias":"东乌珠穆沁旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007889"},{"bank_alias":"镶黄旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007903"},{"bank_alias":"多伦县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007912"},{"bank_alias":"扎赉特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007932"},{"bank_alias":"满洲里农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000007980"},{"bank_alias":"苏尼特右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008002"},{"bank_alias":"内蒙古察哈尔右翼前旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008056"},{"bank_alias":"苏尼特左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008085"},{"bank_alias":"陈巴尔虎旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008087"},{"bank_alias":"正蓝旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008127"},{"bank_alias":"内蒙古鄂托克前旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008171"},{"bank_alias":"内蒙古根河市好里堡农村信用合作社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008182"},{"bank_alias":"突泉县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008207"},{"bank_alias":"内蒙古阿鲁科尔沁农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008258"},{"bank_alias":"准格尔旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008279"},{"bank_alias":"二连浩特农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008337"},{"bank_alias":"准格尔煤田农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008392"},{"bank_alias":"阿拉善右旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008421"},{"bank_alias":"阿荣旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008468"},{"bank_alias":"赤峰市红山区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008473"},{"bank_alias":"锡林浩特农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008474"},{"bank_alias":"内蒙古乌拉特农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008487"},{"bank_alias":"乌拉特后旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008488"},{"bank_alias":"霍林郭勒市农村信用合作社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008500"},{"bank_alias":"内蒙古牙克石农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008509"},{"bank_alias":"内蒙古土默特右旗农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008514"},{"bank_alias":"敖汉旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008599"},{"bank_alias":"内蒙古鄂伦春农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008642"},{"bank_alias":"科尔沁左翼后旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008653"},{"bank_alias":"内蒙古呼和浩特金谷农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008679"},{"bank_alias":"清水河县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008695"},{"bank_alias":"内蒙古乌兰察布市化德县农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008712"},{"bank_alias":"包头市南郊农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008715"},{"bank_alias":"乌兰察布农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008736"},{"bank_alias":"四子王旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008850"},{"bank_alias":"商都县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008917"},{"bank_alias":"固阳县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008928"},{"bank_alias":"达拉特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008931"},{"bank_alias":"丰镇市农村信用联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008937"},{"bank_alias":"喀喇沁旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008981"},{"bank_alias":"内蒙古鄂温克农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000008987"},{"bank_alias":"兴和县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009005"},{"bank_alias":"内蒙古兴安盟科尔沁右翼中旗农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009007"},{"bank_alias":"土默特左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009038"},{"bank_alias":"内蒙古林西农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009040"},{"bank_alias":"莫力达瓦达斡尔族自治旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009042"},{"bank_alias":"内蒙古托克托农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009065"},{"bank_alias":"扎鲁特旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009089"},{"bank_alias":"伊金霍洛旗矿区农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009097"},{"bank_alias":"乌审旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009132"},{"bank_alias":"根河市农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009161"},{"bank_alias":"内蒙古呼伦贝尔市新巴尔虎右旗农村信用合作社联合社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009205"},{"bank_alias":"鄂尔多斯农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009220"},{"bank_alias":"正镶白旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009234"},{"bank_alias":"科尔沁左翼中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009247"},{"bank_alias":"土左旗察素齐信用社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009254"},{"bank_alias":"乌拉特中旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009263"},{"bank_alias":"达尔罕茂明安联合旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009264"},{"bank_alias":"内蒙古鄂托克农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009290"},{"bank_alias":"新巴尔虎左旗农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009348"},{"bank_alias":"呼伦贝尔农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009372"},{"bank_alias":"通辽奈曼农村合作银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009397"},{"bank_alias":"赤峰松山农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009399"},{"bank_alias":"阿拉善农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009400"},{"bank_alias":"磴口县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009421"},{"bank_alias":"卓资县农村信用合作联社","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009462"},{"bank_alias":"内蒙古杭锦农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009702"},{"bank_alias":"内蒙古库伦农村商业银行","need_bank_branch":false,"account_bank":"内蒙古农信","account_bank_code":4158,"bank_alias_code":"1000009704"},{"bank_alias":"安徽石台农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007571"},{"bank_alias":"安徽来安农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007615"},{"bank_alias":"安徽无为农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007660"},{"bank_alias":"安徽涡阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007697"},{"bank_alias":"安徽霍山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007715"},{"bank_alias":"安徽旌德农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007724"},{"bank_alias":"滁州皖东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007730"},{"bank_alias":"芜湖津盛农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007751"},{"bank_alias":"安徽宿州农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007796"},{"bank_alias":"安徽颍上农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007843"},{"bank_alias":"安徽固镇农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007852"},{"bank_alias":"安徽桐城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007885"},{"bank_alias":"安徽定远农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007890"},{"bank_alias":"亳州药都农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007951"},{"bank_alias":"安徽凤阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007975"},{"bank_alias":"阜阳颍东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000007993"},{"bank_alias":"安徽庐江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008043"},{"bank_alias":"铜陵皖江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008069"},{"bank_alias":"安徽阜南农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008112"},{"bank_alias":"安徽临泉农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008119"},{"bank_alias":"铜陵农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008189"},{"bank_alias":"安徽歙县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008238"},{"bank_alias":"阜阳颍淮农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008247"},{"bank_alias":"安徽南陵农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008248"},{"bank_alias":"淮北农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008354"},{"bank_alias":"宣城皖南农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008370"},{"bank_alias":"安徽五河农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008398"},{"bank_alias":"黄山太平农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008404"},{"bank_alias":"池州九华农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008414"},{"bank_alias":"安徽马鞍山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008415"},{"bank_alias":"安徽舒城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008459"},{"bank_alias":"安徽岳西农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008461"},{"bank_alias":"安徽天长农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008490"},{"bank_alias":"安徽宿松农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008522"},{"bank_alias":"安徽绩溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008532"},{"bank_alias":"安徽太和农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008563"},{"bank_alias":"阜阳颍泉农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008576"},{"bank_alias":"六安农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008583"},{"bank_alias":"安徽枞阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008585"},{"bank_alias":"安徽界首农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008589"},{"bank_alias":"安徽黟县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008590"},{"bank_alias":"安徽肥东农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008600"},{"bank_alias":"安徽怀远农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008611"},{"bank_alias":"安徽泾县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008619"},{"bank_alias":"黄山屯溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008625"},{"bank_alias":"安徽东至农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008635"},{"bank_alias":"蚌埠农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008666"},{"bank_alias":"安徽郎溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008676"},{"bank_alias":"安徽灵璧农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008683"},{"bank_alias":"安徽休宁农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008721"},{"bank_alias":"安徽全椒农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008772"},{"bank_alias":"安徽广德农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008798"},{"bank_alias":"安徽长丰农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008805"},{"bank_alias":"安徽砀山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008875"},{"bank_alias":"安徽泗县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008904"},{"bank_alias":"安徽省农村信用社联合社","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008915"},{"bank_alias":"安徽利辛农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008938"},{"bank_alias":"安徽祁门农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008949"},{"bank_alias":"安庆农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000008972"},{"bank_alias":"安徽萧县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009077"},{"bank_alias":"安徽叶集农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009104"},{"bank_alias":"安徽和县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009138"},{"bank_alias":"合肥科技农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009170"},{"bank_alias":"巢湖农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009171"},{"bank_alias":"安徽濉溪农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009175"},{"bank_alias":"安徽繁昌农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009182"},{"bank_alias":"安徽肥西农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009201"},{"bank_alias":"安徽望江农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009223"},{"bank_alias":"芜湖扬子农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009238"},{"bank_alias":"安徽宁国农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009239"},{"bank_alias":"安徽凤台农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009276"},{"bank_alias":"淮南淮河农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009283"},{"bank_alias":"安徽青阳农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009295"},{"bank_alias":"安徽明光农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009298"},{"bank_alias":"安徽怀宁农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009349"},{"bank_alias":"安徽霍邱农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009365"},{"bank_alias":"安徽太湖农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009368"},{"bank_alias":"安徽蒙城农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009379"},{"bank_alias":"安徽寿县农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009401"},{"bank_alias":"黄山徽州农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009403"},{"bank_alias":"淮南通商农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009447"},{"bank_alias":"安徽潜山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009464"},{"bank_alias":"安徽含山农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009470"},{"bank_alias":"安徽金寨农村商业银行","need_bank_branch":false,"account_bank":"安徽省农村信用社","account_bank_code":4166,"bank_alias_code":"1000009472"},{"bank_alias":"天津滨海农村商业银行","need_bank_branch":false,"account_bank":"天津滨海农商行","account_bank_code":4169,"bank_alias_code":"1000007090"},{"bank_alias":"长沙银行","need_bank_branch":false,"account_bank":"长沙银行","account_bank_code":4216,"bank_alias_code":"1000005292"},{"bank_alias":"江苏靖江农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006962"},{"bank_alias":"江苏高邮农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006963"},{"bank_alias":"江苏如皋农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006967"},{"bank_alias":"江苏南通农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006983"},{"bank_alias":"江苏海安农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000006991"},{"bank_alias":"江苏丹阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007006"},{"bank_alias":"江苏镇江农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007014"},{"bank_alias":"江苏淮安农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007015"},{"bank_alias":"连云港东方农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007016"},{"bank_alias":"江苏宜兴农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007024"},{"bank_alias":"江苏睢宁农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007032"},{"bank_alias":"江苏溧水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007041"},{"bank_alias":"江苏邳州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007048"},{"bank_alias":"江苏射阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007053"},{"bank_alias":"江苏赣榆农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007058"},{"bank_alias":"江苏东台农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007064"},{"bank_alias":"江苏建湖农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007069"},{"bank_alias":"江苏句容农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007109"},{"bank_alias":"江苏泗洪农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007135"},{"bank_alias":"江苏扬州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007139"},{"bank_alias":"江苏盱眙农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007165"},{"bank_alias":"江苏阜宁农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007183"},{"bank_alias":"江苏扬中农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007186"},{"bank_alias":"江苏如东农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007187"},{"bank_alias":"江苏泰州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007188"},{"bank_alias":"江苏洪泽农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007190"},{"bank_alias":"江苏新沂农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007201"},{"bank_alias":"江苏高淳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007208"},{"bank_alias":"江苏灌南农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007217"},{"bank_alias":"江苏丰县农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007261"},{"bank_alias":"江苏溧水农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007293"},{"bank_alias":"江苏宝应农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007295"},{"bank_alias":"江苏泗阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007299"},{"bank_alias":"江苏东海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007321"},{"bank_alias":"徐州彭城农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007322"},{"bank_alias":"江苏大丰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007323"},{"bank_alias":"江苏滨海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007332"},{"bank_alias":"江苏金湖农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007354"},{"bank_alias":"江苏宜兴农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007358"},{"bank_alias":"如皋农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007376"},{"bank_alias":"江苏姜堰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007384"},{"bank_alias":"江苏盐城农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007390"},{"bank_alias":"江苏仪征农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007394"},{"bank_alias":"江苏灌云农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007396"},{"bank_alias":"江苏启东农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007398"},{"bank_alias":"江苏江都农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007432"},{"bank_alias":"扬州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007443"},{"bank_alias":"江苏涟水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007451"},{"bank_alias":"江苏沭阳农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007460"},{"bank_alias":"溧水农商行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007463"},{"bank_alias":"江苏泰兴农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007471"},{"bank_alias":"江苏海门农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007476"},{"bank_alias":"徐州淮海农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007480"},{"bank_alias":"江苏沛县农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007481"},{"bank_alias":"徐州铜山农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007482"},{"bank_alias":"江苏响水农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007486"},{"bank_alias":"江苏兴化农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007499"},{"bank_alias":"江苏民丰农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000007510"},{"bank_alias":"徐州农村商业银行","need_bank_branch":false,"account_bank":"江苏省农村信用社","account_bank_code":4217,"bank_alias_code":"1000009733"},{"bank_alias":"湖州银行","need_bank_branch":false,"account_bank":"湖州银行","account_bank_code":4741,"bank_alias_code":"1000005300"},{"bank_alias":"哈密市商业银行","need_bank_branch":false,"account_bank":"哈密银行","account_bank_code":4750,"bank_alias_code":"1000005239"},{"bank_alias":"衡水银行","need_bank_branch":false,"account_bank":"衡水银行","account_bank_code":4752,"bank_alias_code":"1000005223"},{"bank_alias":"中原银行","need_bank_branch":false,"account_bank":"中原银行","account_bank_code":4753,"bank_alias_code":"1000005246"},{"bank_alias":"东营莱商村镇银行","need_bank_branch":false,"account_bank":"东营莱商村镇银行","account_bank_code":4754,"bank_alias_code":"1000005422"},{"bank_alias":"长子县融汇村镇银行","need_bank_branch":false,"account_bank":"长子县融汇村镇银行","account_bank_code":4755,"bank_alias_code":"1000005328"},{"bank_alias":"长治银行","need_bank_branch":false,"account_bank":"长治银行","account_bank_code":4756,"bank_alias_code":"1000005215"},{"bank_alias":"海口联合农村商业银行","need_bank_branch":false,"account_bank":"海口联合农商银行","account_bank_code":4758,"bank_alias_code":"1000007286"},{"bank_alias":"企业银行","need_bank_branch":false,"account_bank":"企业银行","account_bank_code":4761,"bank_alias_code":"1000009605"},{"bank_alias":"渣打银行","need_bank_branch":false,"account_bank":"渣打银行","account_bank_code":4762,"bank_alias_code":"1000009619"},{"bank_alias":"南洋商业银行","need_bank_branch":false,"account_bank":"南洋商业银行","account_bank_code":4763,"bank_alias_code":"1000009574"},{"bank_alias":"浙江上虞农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007527"},{"bank_alias":"浙江富阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007574"},{"bank_alias":"浙江瑞安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007587"},{"bank_alias":"浙江台州椒江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007602"},{"bank_alias":"浙江永康农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007608"},{"bank_alias":"浙江松阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007614"},{"bank_alias":"浙江德清农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007625"},{"bank_alias":"浙江兰溪农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007679"},{"bank_alias":"浙江诸暨农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007683"},{"bank_alias":"浙江桐庐农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007722"},{"bank_alias":"浙江景宁农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007785"},{"bank_alias":"浙江云和农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007819"},{"bank_alias":"宁波北仑农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007877"},{"bank_alias":"浙江龙泉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007952"},{"bank_alias":"浙江新昌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000007974"},{"bank_alias":"浙江绍兴恒信农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008038"},{"bank_alias":"浙江台州路桥农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008047"},{"bank_alias":"浙江玉环农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008076"},{"bank_alias":"浙江建德农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008092"},{"bank_alias":"浙江海宁农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008129"},{"bank_alias":"浙江南浔农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008148"},{"bank_alias":"宁波镇海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008175"},{"bank_alias":"浙江东阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008190"},{"bank_alias":"浙江三门农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008194"},{"bank_alias":"浙江温州龙湾农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008220"},{"bank_alias":"浙江苍南农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008306"},{"bank_alias":"浙江台州黄岩农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008316"},{"bank_alias":"浙江金华成泰农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008333"},{"bank_alias":"浙江温州鹿城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008345"},{"bank_alias":"浙江天台农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008368"},{"bank_alias":"浙江舟山普陀农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008400"},{"bank_alias":"浙江淳安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008443"},{"bank_alias":"浙江临安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008458"},{"bank_alias":"宁波慈溪农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008475"},{"bank_alias":"浙江青田农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008539"},{"bank_alias":"浙江文成农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008540"},{"bank_alias":"浙江龙游农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008572"},{"bank_alias":"杭州联合农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008581"},{"bank_alias":"浙江安吉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008582"},{"bank_alias":"浙江禾城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008602"},{"bank_alias":"浙江开化农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008610"},{"bank_alias":"浙江温岭农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008651"},{"bank_alias":"浙江嵊泗农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008668"},{"bank_alias":"浙江温州洞头农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008674"},{"bank_alias":"舟山定海海洋农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008696"},{"bank_alias":"浙江缙云农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008703"},{"bank_alias":"浙江临海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008719"},{"bank_alias":"浙江常山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008731"},{"bank_alias":"浙江岱山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008740"},{"bank_alias":"浙江丽水莲都农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008744"},{"bank_alias":"浙江义乌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008783"},{"bank_alias":"象山县农村信用合作联社","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008790"},{"bank_alias":"浙江长兴农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008800"},{"bank_alias":"浙江海盐农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008803"},{"bank_alias":"浙江舟山定海海洋农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008836"},{"bank_alias":"浙江平湖农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008839"},{"bank_alias":"宁波余姚农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008859"},{"bank_alias":"浙江桐乡农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008916"},{"bank_alias":"浙江浦江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008922"},{"bank_alias":"浙江平阳农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008927"},{"bank_alias":"宁波奉化农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000008951"},{"bank_alias":"浙江龙湾农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009004"},{"bank_alias":"浙江嵊州农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009025"},{"bank_alias":"浙江泰顺农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009061"},{"bank_alias":"浙江磐安农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009098"},{"bank_alias":"浙江温州瓯海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009100"},{"bank_alias":"浙江绍兴瑞丰农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009119"},{"bank_alias":"浙江永嘉农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009125"},{"bank_alias":"浙江乐清农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009135"},{"bank_alias":"浙江衢州衢江农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009160"},{"bank_alias":"浙江遂昌农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009165"},{"bank_alias":"浙江嘉善农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009178"},{"bank_alias":"浙江萧山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009183"},{"bank_alias":"浙江省农村信用社联合社","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009279"},{"bank_alias":"浙江武义农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009334"},{"bank_alias":"湖州吴兴农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009357"},{"bank_alias":"浙江仙居农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009450"},{"bank_alias":"浙江庆元农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009451"},{"bank_alias":"浙江江山农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009457"},{"bank_alias":"浙江衢州柯城农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009463"},{"bank_alias":"浙江杭州余杭农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009467"},{"bank_alias":"宁波宁海农村商业银行","need_bank_branch":false,"account_bank":"浙江省农村信用社","account_bank_code":4764,"bank_alias_code":"1000009480"},{"bank_alias":"秦皇岛银行","need_bank_branch":false,"account_bank":"秦皇岛银行","account_bank_code":4765,"bank_alias_code":"1000005253"},{"bank_alias":"枣庄银行","need_bank_branch":false,"account_bank":"枣庄银行","account_bank_code":4766,"bank_alias_code":"1000005197"},{"bank_alias":"大同银行","need_bank_branch":false,"account_bank":"大同银行","account_bank_code":4767,"bank_alias_code":"1000005202"},{"bank_alias":"威海蓝海银行","need_bank_branch":false,"account_bank":"蓝海银行","account_bank_code":4768,"bank_alias_code":"1000009509"},{"bank_alias":"北京中关村银行","need_bank_branch":false,"account_bank":"北京中关村银行","account_bank_code":4769,"bank_alias_code":"1000009503"},{"bank_alias":"长城华西银行","need_bank_branch":false,"account_bank":"长城华西银行","account_bank_code":4773,"bank_alias_code":"1000005285"},{"bank_alias":"库尔勒银行","need_bank_branch":false,"account_bank":"库尔勒银行","account_bank_code":4774,"bank_alias_code":"1000005301"},{"bank_alias":"星展银行","need_bank_branch":false,"account_bank":"星展银行","account_bank_code":4778,"bank_alias_code":"1000009612"},{"bank_alias":"中信百信银行","need_bank_branch":false,"account_bank":"百信银行","account_bank_code":4779,"bank_alias_code":"1000009570"},{"bank_alias":"吉林亿联银行","need_bank_branch":false,"account_bank":"亿联银行","account_bank_code":4780,"bank_alias_code":"1000009497"},{"bank_alias":"青县青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005769"},{"bank_alias":"东阿青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005874"},{"bank_alias":"鱼台青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005956"},{"bank_alias":"东光青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000005996"},{"bank_alias":"高唐青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006152"},{"bank_alias":"莘县青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006156"},{"bank_alias":"黄骅青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006469"},{"bank_alias":"沧州市运河青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006616"},{"bank_alias":"桓台青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006636"},{"bank_alias":"山东周村青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006762"},{"bank_alias":"山东邹平青隆村镇银行","need_bank_branch":false,"account_bank":"青隆村镇银行","account_bank_code":4781,"bank_alias_code":"1000006921"},{"bank_alias":"长春南关惠民村镇银行","need_bank_branch":false,"account_bank":"长春南关惠民村镇银行","account_bank_code":4782,"bank_alias_code":"1000006425"},{"bank_alias":"湖北银行","need_bank_branch":false,"account_bank":"湖北银行","account_bank_code":4783,"bank_alias_code":"1000005272"},{"bank_alias":"齐河胶东村镇银行","need_bank_branch":false,"account_bank":"齐河胶东村镇银行","account_bank_code":4784,"bank_alias_code":"1000005677"},{"bank_alias":"南阳村镇银行","need_bank_branch":false,"account_bank":"南阳村镇银行","account_bank_code":4785,"bank_alias_code":"1000006018"},{"bank_alias":"湖南三湘银行","need_bank_branch":false,"account_bank":"三湘银行","account_bank_code":4787,"bank_alias_code":"1000009498"},{"bank_alias":"前郭县阳光村镇银行","need_bank_branch":false,"account_bank":"前郭县阳光村镇银行","account_bank_code":4788,"bank_alias_code":"1000006798"},{"bank_alias":"宁夏中宁青银村镇银行","need_bank_branch":false,"account_bank":"中宁青银村镇银行","account_bank_code":4789,"bank_alias_code":"1000005590"},{"bank_alias":"绥阳黔北村镇银行","need_bank_branch":false,"account_bank":"绥阳黔北村镇银行","account_bank_code":4790,"bank_alias_code":"1000006864"},{"bank_alias":"长春经开融丰村镇银行","need_bank_branch":false,"account_bank":"长春经开融丰村镇银行","account_bank_code":4791,"bank_alias_code":"1000005611"},{"bank_alias":"沙河襄通村镇银行","need_bank_branch":false,"account_bank":"沙河襄通村镇银行","account_bank_code":4794,"bank_alias_code":"1000005693"},{"bank_alias":"垦利乐安村镇银行","need_bank_branch":false,"account_bank":"垦利乐安村镇银行","account_bank_code":4795,"bank_alias_code":"1000006763"},{"bank_alias":"花旗银行","need_bank_branch":false,"account_bank":"花旗银行","account_bank_code":4796,"bank_alias_code":"1000009591"},{"bank_alias":"长春朝阳和润村镇银行","need_bank_branch":false,"account_bank":"长春朝阳和润村镇银行","account_bank_code":4797,"bank_alias_code":"1000006730"},{"bank_alias":"江苏银行","need_bank_branch":false,"account_bank":"江苏银行","account_bank_code":4830,"bank_alias_code":"1000005302"},{"bank_alias":"北京银行","need_bank_branch":false,"account_bank":"北京银行","account_bank_code":4836,"bank_alias_code":"1000005194"},{"bank_alias":"襄垣县融汇村镇银行","need_bank_branch":false,"account_bank":"襄垣县融汇村镇银行","account_bank_code":4842,"bank_alias_code":"1000006438"},{"bank_alias":"德州银行","need_bank_branch":false,"account_bank":"德州银行","account_bank_code":4843,"bank_alias_code":"1000005306"},{"bank_alias":"晋商银行","need_bank_branch":false,"account_bank":"晋商银行","account_bank_code":4844,"bank_alias_code":"1000005293"},{"bank_alias":"法国巴黎银行","need_bank_branch":false,"account_bank":"法国巴黎银行","account_bank_code":4845,"bank_alias_code":"1000009645"},{"bank_alias":"新疆绿洲国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005344"},{"bank_alias":"克拉玛依金龙国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005428"},{"bank_alias":"伊犁国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005506"},{"bank_alias":"平果国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005507"},{"bank_alias":"昌吉国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005640"},{"bank_alias":"广西银海国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005724"},{"bank_alias":"博乐国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005755"},{"bank_alias":"东兴国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005848"},{"bank_alias":"石河子国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000005999"},{"bank_alias":"哈密红星国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006136"},{"bank_alias":"五家渠国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006274"},{"bank_alias":"库车国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006451"},{"bank_alias":"防城港防城国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006475"},{"bank_alias":"广西钦州市钦南国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006546"},{"bank_alias":"北屯国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006554"},{"bank_alias":"奎屯国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006585"},{"bank_alias":"广西浦北国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006681"},{"bank_alias":"广西上林国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006706"},{"bank_alias":"邛崃国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006753"},{"bank_alias":"宁波市海曙国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006806"},{"bank_alias":"合浦国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006816"},{"bank_alias":"象山国民村镇银行","need_bank_branch":false,"account_bank":"国民村镇银行","account_bank_code":4862,"bank_alias_code":"1000006841"},{"bank_alias":"山东临朐聚丰村镇银行","need_bank_branch":false,"account_bank":"山东临朐聚丰村镇银行","account_bank_code":4864,"bank_alias_code":"1000006406"},{"bank_alias":"香河益民村镇银行","need_bank_branch":false,"account_bank":"香河益民村镇银行","account_bank_code":4865,"bank_alias_code":"1000006449"},{"bank_alias":"辽宁岫岩金玉村镇银行","need_bank_branch":false,"account_bank":"辽宁岫岩金玉村镇银行","account_bank_code":4866,"bank_alias_code":"1000006900"},{"bank_alias":"阳城县三禾村镇银行","need_bank_branch":false,"account_bank":"阳城县三禾村镇银行","account_bank_code":4867,"bank_alias_code":"1000005458"},{"bank_alias":"永济市三禾村镇银行","need_bank_branch":false,"account_bank":"永济市三禾村镇银行","account_bank_code":4868,"bank_alias_code":"1000006415"},{"bank_alias":"禹城胶东村镇银行","need_bank_branch":false,"account_bank":"禹城胶东村镇银行","account_bank_code":4869,"bank_alias_code":"1000005963"},{"bank_alias":"遵义播州汇隆村镇银行","need_bank_branch":false,"account_bank":"遵义播州汇隆村镇银行","account_bank_code":4870,"bank_alias_code":"1000006000"},{"bank_alias":"辽宁辰州汇通村镇银行","need_bank_branch":false,"account_bank":"辽宁辰州汇通村镇银行","account_bank_code":4871,"bank_alias_code":"1000005917"},{"bank_alias":"辽宁大石桥隆丰村镇银行","need_bank_branch":false,"account_bank":"辽宁大石桥隆丰村镇银行","account_bank_code":4872,"bank_alias_code":"1000006764"},{"bank_alias":"大洼恒丰村镇银行","need_bank_branch":false,"account_bank":"大洼恒丰村镇银行","account_bank_code":4874,"bank_alias_code":"1000005405"},{"bank_alias":"盘山安泰村镇银行","need_bank_branch":false,"account_bank":"盘山安泰村镇银行","account_bank_code":4875,"bank_alias_code":"1000005468"},{"bank_alias":"沂源博商村镇银行","need_bank_branch":false,"account_bank":"沂源博商村镇银行","account_bank_code":4876,"bank_alias_code":"1000005949"},{"bank_alias":"桂林国民村镇银行","need_bank_branch":false,"account_bank":"桂林国民村镇银行","account_bank_code":4877,"bank_alias_code":"1000006022"},{"bank_alias":"元氏信融村镇银行","need_bank_branch":false,"account_bank":"元氏信融村镇银行","account_bank_code":4878,"bank_alias_code":"1000006423"},{"bank_alias":"山东历城圆融村镇银行","need_bank_branch":false,"account_bank":"历城圆融村镇银行","account_bank_code":4879,"bank_alias_code":"1000005682"},{"bank_alias":"南宁江南国民村镇银行","need_bank_branch":false,"account_bank":"南宁江南国民村镇银行","account_bank_code":4880,"bank_alias_code":"1000005408"},{"bank_alias":"平坝鼎立村镇银行","need_bank_branch":false,"account_bank":"平坝鼎立村镇银行","account_bank_code":4881,"bank_alias_code":"1000005552"},{"bank_alias":"上海闵行上银村镇银行","need_bank_branch":false,"account_bank":"闵行上银村镇银行","account_bank_code":4882,"bank_alias_code":"1000005783"},{"bank_alias":"内江兴隆村镇银行","need_bank_branch":false,"account_bank":"内江兴隆村镇银行","account_bank_code":4883,"bank_alias_code":"1000006398"},{"bank_alias":"庆阳市西峰瑞信村镇银行","need_bank_branch":false,"account_bank":"瑞信村镇银行","account_bank_code":4884,"bank_alias_code":"1000005550"},{"bank_alias":"东方惠丰村镇银行","need_bank_branch":false,"account_bank":"东方惠丰村镇银行","account_bank_code":4885,"bank_alias_code":"1000005687"},{"bank_alias":"东方汇理银行","need_bank_branch":false,"account_bank":"东方汇理银行","account_bank_code":4912,"bank_alias_code":"1000009625"},{"bank_alias":"贵阳农村商业银行","need_bank_branch":false,"account_bank":"贵阳农商银行","account_bank_code":4917,"bank_alias_code":"1000007174"},{"bank_alias":"德州陵城圆融村镇银行","need_bank_branch":false,"account_bank":"陵城圆融村镇银行","account_bank_code":5712,"bank_alias_code":"1000006506"},{"bank_alias":"费县梁邹村镇银行","need_bank_branch":false,"account_bank":"费县梁邹村镇银行","account_bank_code":5713,"bank_alias_code":"1000005665"},{"bank_alias":"牟平胶东村镇银行","need_bank_branch":false,"account_bank":"牟平胶东村镇银行","account_bank_code":5714,"bank_alias_code":"1000006793"},{"bank_alias":"武安村镇银行","need_bank_branch":false,"account_bank":"武安村镇银行","account_bank_code":5716,"bank_alias_code":"1000005486"},{"bank_alias":"呼和浩特市玉泉蒙银村镇银行","need_bank_branch":false,"account_bank":"玉泉蒙银村镇银行","account_bank_code":5717,"bank_alias_code":"1000006599"},{"bank_alias":"任丘村镇银行","need_bank_branch":false,"account_bank":"任丘村镇银行","account_bank_code":5718,"bank_alias_code":"1000005658"},{"bank_alias":"遵义新蒲长征村镇银行","need_bank_branch":false,"account_bank":"遵义新蒲长征村镇银行","account_bank_code":5722,"bank_alias_code":"1000006829"},{"bank_alias":"六盘水钟山凉都村镇银行","need_bank_branch":false,"account_bank":"钟山凉都村镇银行","account_bank_code":5723,"bank_alias_code":"1000006060"},{"bank_alias":"保德县慧融村镇银行","need_bank_branch":false,"account_bank":"保德慧融村镇银行","account_bank_code":5724,"bank_alias_code":"1000006856"},{"bank_alias":"廊坊市广阳舜丰村镇银行","need_bank_branch":false,"account_bank":"广阳舜丰村镇银行","account_bank_code":5726,"bank_alias_code":"1000005398"},{"bank_alias":"大城舜丰村镇银行","need_bank_branch":false,"account_bank":"大城舜丰村镇银行","account_bank_code":5728,"bank_alias_code":"1000006583"},{"bank_alias":"山东沾化青云村镇银行","need_bank_branch":false,"account_bank":"沾化青云村镇银行","account_bank_code":5729,"bank_alias_code":"1000005350"},{"bank_alias":"夏津胶东村镇银行","need_bank_branch":false,"account_bank":"夏津胶东村镇银行","account_bank_code":5730,"bank_alias_code":"1000006463"},{"bank_alias":"山东兰陵村镇银行","need_bank_branch":false,"account_bank":"山东兰陵村镇银行","account_bank_code":5731,"bank_alias_code":"1000005662"},{"bank_alias":"安顺西航南马村镇银行","need_bank_branch":false,"account_bank":"安顺西航南马村镇银行","account_bank_code":5732,"bank_alias_code":"1000006567"},{"bank_alias":"调兵山惠民村镇银行","need_bank_branch":false,"account_bank":"调兵山惠民村镇银行","account_bank_code":5733,"bank_alias_code":"1000006737"},{"bank_alias":"宁津胶东村镇银行","need_bank_branch":false,"account_bank":"宁津胶东村镇银行","account_bank_code":5734,"bank_alias_code":"1000005892"},{"bank_alias":"浙江浦江嘉银村镇银行","need_bank_branch":false,"account_bank":"浦江嘉银村镇银行","account_bank_code":5735,"bank_alias_code":"1000006083"},{"bank_alias":"德江长征村镇银行","need_bank_branch":false,"account_bank":"德江长征村镇银行","account_bank_code":5737,"bank_alias_code":"1000005704"},{"bank_alias":"江口长征村镇银行","need_bank_branch":false,"account_bank":"江口长征村镇银行","account_bank_code":5738,"bank_alias_code":"1000006361"},{"bank_alias":"石阡长征村镇银行","need_bank_branch":false,"account_bank":"石阡长征村镇银行","account_bank_code":5739,"bank_alias_code":"1000006368"},{"bank_alias":"松桃长征村镇银行","need_bank_branch":false,"account_bank":"松桃长征村镇银行","account_bank_code":5740,"bank_alias_code":"1000005419"},{"bank_alias":"铜仁万山长征村镇银行","need_bank_branch":false,"account_bank":"铜仁万山长征村镇银行","account_bank_code":5741,"bank_alias_code":"1000006791"},{"bank_alias":"江苏江都吉银村镇银行","need_bank_branch":false,"account_bank":"江苏江都吉银村镇银行","account_bank_code":5744,"bank_alias_code":"1000005599"},{"bank_alias":"正蓝旗汇泽村镇银行","need_bank_branch":false,"account_bank":"正蓝旗汇泽村镇银行","account_bank_code":5745,"bank_alias_code":"1000006621"},{"bank_alias":"永清吉银村镇银行","need_bank_branch":false,"account_bank":"永清吉银村镇银行","account_bank_code":5746,"bank_alias_code":"1000005794"},{"bank_alias":"东丰吉银村镇银行","need_bank_branch":false,"account_bank":"东丰吉银村镇银行","account_bank_code":5747,"bank_alias_code":"1000006259"},{"bank_alias":"双辽吉银村镇银行","need_bank_branch":false,"account_bank":"双辽吉银村镇银行","account_bank_code":5748,"bank_alias_code":"1000006386"},{"bank_alias":"长春双阳吉银村镇银行","need_bank_branch":false,"account_bank":"长春双阳吉银村镇银行","account_bank_code":5749,"bank_alias_code":"1000006411"},{"bank_alias":"威海富民村镇银行","need_bank_branch":false,"account_bank":"威海富民村镇银行","account_bank_code":5750,"bank_alias_code":"1000006711"},{"bank_alias":"乐东惠丰村镇银行","need_bank_branch":false,"account_bank":"乐东惠丰村镇银行","account_bank_code":5751,"bank_alias_code":"1000005958"},{"bank_alias":"临高惠丰村镇银行","need_bank_branch":false,"account_bank":"临高惠丰村镇银行","account_bank_code":5752,"bank_alias_code":"1000006663"},{"bank_alias":"右玉县长青村镇银行","need_bank_branch":false,"account_bank":"右玉县长青村镇银行","account_bank_code":5753,"bank_alias_code":"1000005919"},{"bank_alias":"山东高青汇金村镇银行","need_bank_branch":false,"account_bank":"山东高青汇金村镇银行","account_bank_code":5755,"bank_alias_code":"1000006817"},{"bank_alias":"灵丘县长青村镇银行","need_bank_branch":false,"account_bank":"灵丘县长青村镇银行","account_bank_code":5756,"bank_alias_code":"1000005886"},{"bank_alias":"左云县长青村镇银行","need_bank_branch":false,"account_bank":"左云县长青村镇银行","account_bank_code":5757,"bank_alias_code":"1000005667"},{"bank_alias":"唐县汇泽村镇银行","need_bank_branch":false,"account_bank":"唐县汇泽村镇银行","account_bank_code":5758,"bank_alias_code":"1000006205"},{"bank_alias":"霸州舜丰村镇银行","need_bank_branch":false,"account_bank":"霸州舜丰村镇银行","account_bank_code":5759,"bank_alias_code":"1000006733"},{"bank_alias":"贵阳白云德信村镇银行","need_bank_branch":false,"account_bank":"贵阳白云德信村镇银行","account_bank_code":5760,"bank_alias_code":"1000005330"},{"bank_alias":"宝丰豫丰村镇银行","need_bank_branch":false,"account_bank":"宝丰豫丰村镇银行","account_bank_code":5761,"bank_alias_code":"1000005726"},{"bank_alias":"昌乐乐安村镇银行","need_bank_branch":false,"account_bank":"昌乐乐安村镇银行","account_bank_code":5762,"bank_alias_code":"1000006634"},{"bank_alias":"唐山市丰南舜丰村镇银行","need_bank_branch":false,"account_bank":"唐山市丰南舜丰村镇银行","account_bank_code":5763,"bank_alias_code":"1000006482"},{"bank_alias":"遵义汇川黔兴村镇银行","need_bank_branch":false,"account_bank":"遵义汇川黔兴村镇银行","account_bank_code":5766,"bank_alias_code":"1000005942"},{"bank_alias":"山东惠民舜丰村镇银行","need_bank_branch":false,"account_bank":"山东惠民舜丰村镇银行","account_bank_code":5767,"bank_alias_code":"1000006477"},{"bank_alias":"鄂尔多斯市康巴什村镇银行","need_bank_branch":false,"account_bank":"鄂尔多斯市康巴什村镇银行","account_bank_code":5768,"bank_alias_code":"1000005753"},{"bank_alias":"莱阳胶东村镇银行","need_bank_branch":false,"account_bank":"莱阳胶东村镇银行","account_bank_code":5769,"bank_alias_code":"1000005709"},{"bank_alias":"山东利津舜丰村镇银行","need_bank_branch":false,"account_bank":"山东利津舜丰村镇银行","account_bank_code":5772,"bank_alias_code":"1000006710"},{"bank_alias":"山东临淄汇金村镇银行","need_bank_branch":false,"account_bank":"山东临淄汇金村镇银行","account_bank_code":5773,"bank_alias_code":"1000006208"},{"bank_alias":"娄烦县三禾村镇银行","need_bank_branch":false,"account_bank":"娄烦县三禾村镇银行","account_bank_code":5774,"bank_alias_code":"1000005779"},{"bank_alias":"南江农科村镇银行","need_bank_branch":false,"account_bank":"南江农科村镇银行","account_bank_code":5776,"bank_alias_code":"1000006414"},{"bank_alias":"黔西花都村镇银行","need_bank_branch":false,"account_bank":"黔西花都村镇银行","account_bank_code":5779,"bank_alias_code":"1000006344"},{"bank_alias":"庆云乐安村镇银行","need_bank_branch":false,"account_bank":"庆云乐安村镇银行","account_bank_code":5781,"bank_alias_code":"1000006150"},{"bank_alias":"仁怀蒙银村镇银行","need_bank_branch":false,"account_bank":"仁怀蒙银村镇银行","account_bank_code":5782,"bank_alias_code":"1000006722"},{"bank_alias":"水城蒙银村镇银行","need_bank_branch":false,"account_bank":"水城蒙银村镇银行","account_bank_code":5783,"bank_alias_code":"1000005644"},{"bank_alias":"浙江松阳恒通村镇银行","need_bank_branch":false,"account_bank":"浙江松阳恒通村镇银行","account_bank_code":5784,"bank_alias_code":"1000006609"},{"bank_alias":"屯留县三禾村镇银行","need_bank_branch":false,"account_bank":"屯留县三禾村镇银行","account_bank_code":5786,"bank_alias_code":"1000006890"},{"bank_alias":"安徽新安银行","need_bank_branch":false,"account_bank":"安徽新安银行","account_bank_code":5789,"bank_alias_code":"1000009505"},{"bank_alias":"荥阳利丰村镇银行","need_bank_branch":false,"account_bank":"利丰村镇银行","account_bank_code":5791,"bank_alias_code":"1000005767"},{"bank_alias":"洛阳银行","need_bank_branch":false,"account_bank":"洛阳银行","account_bank_code":5794,"bank_alias_code":"1000005217"}] \ No newline at end of file diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/templates/lkltkpay/indexHTKWECHAT_PAY.html.ftl b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/lkltkpay/indexHTKWECHAT_PAY.html.ftl new file mode 100644 index 0000000..c247d6d --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/lkltkpay/indexHTKWECHAT_PAY.html.ftl @@ -0,0 +1,462 @@ + + + + + + +

+
+
+
+
+
+ 特约商户支付服务合作协议 +
+
+
+
+ 《特约商户支付服务合作协议》(以下简称“本协议”)是拉卡拉支付股份有限公司(正文部分简称“乙方”)与您(是指接受拉卡拉支付服务的个人或公司法人及相关单位组织等,正文部分简称“甲方”)就“支付服务业务”服务(以下简称“本服务”)所订立的有效合约。 + 您在使用本服务之前,请仔细阅读本协议(特别是以粗体标注的内容),您在拉卡拉客户经理向您展示的本协议上签字,即表示您同意接受本协议的全部内容。如果您不同意本协议的任意内容,或者无法准确理解相关条款,请不要签字。 +
+
+
+
甲方:(特约商户)${fee.customerName} +
+
乙方:(支付机构)拉卡拉支付股份有限公司
+
+
+
第一条 业务服务及费用:
+
1.双方确认,乙方向甲方提供支付服务。
+
+ 2.甲方使用本服务将会产生相应的收单手续费(详见《拉卡拉商户注册登记表》),甲方也可通过APP查询收单手续费。 +
+
+ 3.乙方保留调整本协议项下的费用之权利,如本协议项下的费用调整,乙方将以公告方式在拉卡拉网站提示并予以公示,而无需另行通知甲方,调整后的费用标准在公告期届满之日起生效。若甲方在费用标准调整后继续使用本服务的,视为甲方接受费用标准的调整。若甲方不同意调整后的费用标准,应停止使用本服务并与乙方联系。 +
+
第二条 + 甲方如使用移动通讯受理终端(含内置Esim卡),甲方应向乙方另行支付运营服务费(详见《拉卡拉商户注册登记表》),运营服务包括终端网络维护,质量管理,应急响应等,服务期自终端入网之日起1年。甲方应自本协议生效之日起1个工作日内向乙方支付首年运营服务费,首年服务到期30日前向乙方支付次年运营服务费,以此类推。 +
+
+
+
第三条 + 乙方应将甲方的交易资金在扣除本协议约定的手续费和其他款项后,在约定的结算周期(详见《拉卡拉商户注册登记表》)内,向甲方指定的结算账户划付资金,境外卡支付业务在3个工作日内划付资金。甲方可根据需求选择开通交易发生日结算,乙方审核通过后,将另行扣收相应的快速结算手续费1,具体以拉卡拉商户通APP展示的为准。 +
+
+
+
第四条 + 甲方默认开通退货功能,当甲方发生退货、撤销、冲正交易情形时,乙方有权采用以下一或多种模式将退款资金扣除:(1)从甲方退款终端交易资金中直接扣除;(2)从甲方退款商户交易资金中直接扣除;(3)从甲方退货账户资金中直接扣除;(4)从甲方合作平台/集团商户退货账户资金中直接扣除。如甲方需关闭退货功能,甲方可拨打乙方客服电话95016关闭退货功能。 +
+
+ 对甲方、合作平台/集团商户退货账户进行扣款后,甲方同意并授权乙方依据实际情况将甲方交易资金回充至相应退货账户。甲方因退货操作错误等原因造成的资金风险及损失由甲方承担。 +
+
+
+
第五条 + 乙方应按国家法律法规履行支付机构相关责任与义务。 +
+
+
+
第六条 + 乙方(含乙方分支机构、合作方,下同)为甲方提供的受理终端(包含收款码)仅限甲方在固定地区使用。 + 甲方应提供符合受理终端安装要求的场地条件,并妥善保管和使用,如因甲方管理或使用不当造成终端损坏或遗失的,甲方应按市场价向乙方赔偿,赔付方式为现金、转账或授权乙方从甲方终端押金、交易资金等途径扣除。 + 双方协议终止时,乙方有权收回放置在甲方的受理终端或关闭网络支付接口。 +
+
+
+
第七条 + 受理终端收费标准由乙方与甲方另行约定。固定受理终端、移动受理终端、扫码受理终端数量及型号以拉卡拉客户端及拉卡拉商户通APP展示的数量及型号为准。 +
+
+
+
第八条 + 甲方应准确填写附件《拉卡拉商户注册登记表》中的相关信息,当甲方的工商注册名称、主营业务、法定代表人或负责人、结算账户信息等重要信息发生变更时,甲方应通过乙方官方渠道方式告知乙方,乙方有权重新审核甲方支付业务受理资质。 + 当乙方认为甲方不再具备受理资质时,乙方有权单方面终止本协议。 甲方申请成为乙方特约商户,应主动如实提供经营资质材料及身份证明文件。 + 甲方应保证上述资料完整、真实、合法、有效。若身份证明文件存在有效期,应在有效期前主动向乙方提供新的证明文件,证明文件失效且经乙方提示仍无合理理由拒绝更新的,乙方有权对甲方采取交易限制措施或终止向甲方提供本协议项下相关的服务。 +
+
+
+
第九条 + 甲方应当履行以下基本义务: +
+ 1.基于真实的商品或服务交易背景受理银行卡,并遵守相应银行卡品牌的受理要求,不得歧视和拒绝同一银行卡品牌的不同发卡银行的持卡人; +
+
+ 2.按规定使用受理终端(网络支付接口)和收单结算账户,不得利用其从事或协助他人从事非法活动; +
+
3.妥善处理交易数据信息、保存交易凭证,保障交易信息安全; +
+
+ 4.不得因持卡人使用银行卡而向持卡人收取或变相收取附加费用,或降低服务水平; +
+
+ 5.不得存储持卡人银行卡的磁道信息或芯片信息、验证码、有效期、密码等敏感信息; +
+
6.确保网络支付指令的真实性、准确性、合法性;
+
+ 7.仅在中华人民共和国境内(不包含香港特别行政区、澳门特别行政区及台湾地区)使用本支付服务。 +
+
+
+
+
第十条 + 对经查实的交易差错或甲方需调整的账务,乙方负责按照中国银联或其他卡组织差错处理的有关规定进行相应处理。对有疑议的交易,乙方有权向甲方调单。 +
+
+
+
第十一条 + 甲方需保存所有交易的签购单及其他的交易证明材料,保存期限自交易日起至少2年,如因甲方资料保存不善造成的风险损失由甲方自行承担。 +
+
+
+
第十二条 + 在出现交易纠纷、持卡人调退单或乙方有合理理由认定交易有可疑之处时,乙方有权查验甲方原始交易签购单及相关交易证明材料,并影印留存。 + 甲方应根据乙方要求提供真实的交易受理情况,对于乙方提出的调取交易证明材料的要求,甲方应自乙方通知之日(含)起3个工作日内提供有效交易证明材料。 +
+
+
+
第十三条 + 甲方发生以下情况时,乙方有权采取暂缓甲方全部或部分交易资金结算至少180天以上: +
+
1.发卡行发起调、退单;
+
2.超出约定地理范围使用终端或终端位置无法监测的; +
+
+ 3.交易金额、时间、频率与甲方经营范围、规模不相符等异常情形;
+
4.疑似虚假申请、银行卡套现、洗钱、欺诈、移机、留存或泄漏持卡人账户信息等风险事件; +
+
5.从事其他违反国家法律法规规定的犯罪、违法活动; +
+
6.乙方认为甲方调退单比例过高、交易纠纷比例过高或有合理理由认定交易存在可疑之处,或有合理根据怀疑甲方违反本协议的其他行为; +
+
7.被工商等管理部门吊销营业执照或行政许可等,从而丧失本协议所列经营资格的; +
+
8.将乙方支付接口用于非本协议约定业务或提供给本协议约定外的第三人使用。 +
+
+ 甲方发生以上第2-8项情况时,乙方同时有权设置收款限额、暂停银行卡交易、收回受理终端、关闭网络支付接口、单方面无条件终止本协议等措施,由此带给乙方的相关损失和风险责任由甲方承担。 + 且乙方有权将甲方相关信息报送至中国银联或其他卡组织风险信息共享系统及中国支付清算协会风险信息共享系统,并向执法、监管部门、相关征信机构通报,发现甲方涉嫌电信网络新型违法犯罪的,乙方还有权立即向公安机关报告。 +
+
+
+
第十四条 + 发生以下情况时,乙方有权从甲方押金、保证金及交易资金中抵扣相应款项,如前述款项不足抵扣的,甲方应根据乙方要求补足差额资金。对因甲方原因造成的乙方垫款或损失,乙方有权向甲方追索。 +
1.甲方发生退货、冲正、撤销交易;
+
2.由于计算错误或其它原因导致乙方向甲方多支付的款项或其它经甲方确认的长款; +
+
+ 3.因甲方原因导致的发卡机构退单或卡组织追究乙方违约金;
+
4.名义经营范围与实际情况不符而造成的本协议项下的费用差额补偿部分(补偿部分的时限为自发现日起前180天); +
+
+ 5.甲方违反本协议约定,导致乙方先行垫付相关方赔偿还款的;
+
6.其它应由甲方支付的款项。
+
本条款不随双方协议终止而终止,乙方在法律规定的诉讼时效内,均有权就合作期间甲方因本条款给乙方造成的损失向甲方追索。 +
+
+
+
+
第十五条 + 乙方有权对甲方进行风险评级,如甲方风险等级较高,乙方对其开通的受理卡种和交易类型进行限制,并采取强化交易监测、设置交易限额、延迟结算、增加检查频率、建立特约商户风险准备金等风险管理措施。 +
+
+
+
第十六条 + 乙方有权对甲方经营场所进行现场检查,如甲方无固定经营场所,乙方有权要求甲方定期上传经营影像或照片。 +
+
+
+
第十七条 + 如甲方连续3个月未发生交易的,乙方有权重新核验甲方商户身份,如无法核实或核实后不再具备受理资质时,乙方有权单方面终止本协议; + 如甲方连续12个月未发生交易的,乙方有权单方面终止本协议。 +
+
+
+
第十八条 + 乙方除有权根据本协议及附件约定外,还有权根据中国人民银行、中国银联、境外卡组织、中国清算协会已发布的及后续发布的各类通知、要求、指导意见等规范性文件内容对甲方进行监督管理并采取必要措施。 +
+
+
+
第十九条 甲方所有在线操作包括在乙方网站、业务系统、微信服务平台、APP等的操作和交易,甲方的登录账号和密码是乙方验证甲方身份的重要印签,甲方对此负有保密责任。 + 凡使用甲方登录账号和密码进行的线上操作和交易均视为甲方亲自办理的有效委托,具有同书面委托同等的法律效力。 + 甲方对使用甲方登录账号和密码进行的所有线上操作及交易结果承担全部经济和法律责任,有证据证明系乙方原因导致甲方账号、密码泄露的情形除外。 +
+ +
+
+
第二十条 + 甲方同意并指定数据处理方(含其分支机构及总公司,详见《拉卡拉商户注册登记表》)为其提供数据处理服务,同意并授权数据处理方为终端布放与受理标识张贴、终端维护、商户培训、耗材配送、交易证明材料调取、对账目的收集、 + 存储并向乙方传送甲方通过线下或线上方式提供的入网信息(包括但不限于《拉卡拉商户注册登记表》中的信息、商户提交的电子版及纸质版资料以及监管部门要求的其他信息),同意并授权乙方将甲方金融信息(包括甲方企业名称、统一社会信用代码、法定代表人姓名及证件号码、经营地址、联系人姓名及证件号码、联系人手机号、联系人电子邮箱、结算账户信息、交易数据、入账信息、对账单明细数据,下同)提供给数据处理方,同意并授权数据处理方从乙方接收并处理前述甲方相关信息。 + 乙方已要求数据处理方按照国家法律法规规定对该等信息采取安全保护措施。若甲方不同意前述授权,甲方可拨打乙方客服电话95016,取消授权。 +
+
+
+
第二十一条 + 甲方同意并授权乙方直接或通过数据处理方接收并按以下方式使用甲方信息将甲方通过线下或线上方式提供的入网信息(包括但不限于《拉卡拉商户注册登记表》中的信息、商户提交的电子版及纸质版资料以及监管部门要求的其他信息)用于乙方支付业务特约商户入网审核、反洗钱管理、实名制管理、风控评估。 + 同时,甲方同意并授权乙方以加密传输方式将甲方信息共享给具备提供验证服务资质的第三方机构进行一致性比对并输出核验结果,同意并授权第三方机构使用甲方的信息用于验证服务并以加密传输的方式向乙方返回核验结果。 +
+
+
+
第二十二条 + 鉴于甲方结算账户所属银行会不定期开展商户手续费补贴等营销活动,甲方同意乙方推荐甲方参加结算行账户所属银行的营销活动,将甲方金融信息提供给甲方结算账户所属银行(包括该银行相关分支行),用于评估甲方是否符合活动要求,对营销活动期间相关数据进行风控管理、考核对账的目的,甲方同意并授权银行从乙方接收并处理前述甲方相关信息。乙方已要求银行按照国家法律法规规定对该等信息采取安全保护措施。若甲方不同意前述授权,甲方可拨打乙方客服电话95016,取消授权。 +
+
+
+
第二十三条 + 乙方将对甲方金融信息严格保密,除本协议约定情形外,不会泄露或者非法向他人提供甲方金融信息。 +
+
+
+
第二十四条 + 本协议执行过程中,如中国人民银行、中国银联、境外卡组织等相关监管机构或行业组织的相关规定或乙方业务规则、市场政策发生变化,导致支付业务规则发生变化或者本协议项下的费用发生变化,乙方可以单方面调整相关条款约定。 +
+
甲方理解并同意乙方采取在官方网站公告、电子服务渠道信息推送、邮件或短信通知等方式向甲方发起变更通知。如甲方不同意该变更后的内容,应停止使用乙方服务; + 如甲方在获知或在合理时限内应当获知乙方变更通知后,仍继续使用乙方服务的,视为同意对协议涉及条款进行变更。
+
+
+
第二十五条 + 甲方可通过【拉卡拉商户通APP】或客服热线95016进行业务咨询、查账、投诉等操作。 +
+
+
+
+
第二十六条 + 任何一方违反本协议约定,另一方有权要求在合理期限内纠正,要求赔偿因此遭受的直接经济损失。但任何一方均无须向对方的间接损失、预期利益承担赔偿责任。 +
+
+
+
第二十七条 + 除本协议另有约定外,双方均有权根据业务需要单方解除或终止本协议,但应提前30天通知对方。 +
+
+
+
第二十八条 通知
+
+ 1.甲方确认,其在《拉卡拉商户注册登记表》中指定的“联系人”、“联系地址”、“联系人电子邮箱”、“联系人电话”等联系信息可用于乙方处理本协议项下事务时向甲方履行通知、文件物品递送义务。 + 其中,“联系人”负责对本协议所涉事务的沟通、文件物品的签收、移交等事宜。乙方发送到甲方指定的“联系地址”、“联系人电子邮箱”即视为对甲方的有效送达。 +
+
+ 2.甲方确认,其变更《拉卡拉商户注册登记表》中指定的联系信息时,应至少提前5个工作日以书面方式通知乙方。因甲方未及时通知导致乙方依照本协议约定联系信息履行通知、文件物品递送义务的,乙方的通知、文件物品(包括但不限于设备、文件及资料等)自发送之日起第3个工作日(含)视为乙方送达之日。
+
+
+
第二十九条 争议解决 +
+ 1.双方在履行本协议过程中发生的任何争议双方应首先协商解决,协商不成,任何一方可将该争议提请上海国际经济贸易仲裁委员会按照该会仲裁规则进行仲裁。 +
+
+ 2.由于计算错误或其它原因导致乙方向甲方多支付的款项或其它经甲方确认的长款。 +
+
+ 3.因甲方原因导致的发卡机构退单或卡组织追究乙方违约金。 +
+
+
+
+
第三十条 协议生效
+
1. 本协议自甲方签字后生效,有效期为一年。 + 有效期届满后如双方无任何书面异议,本协议将自动延期,每次延期一年,依此类推。若甲乙任何一方对延期有异议,应于协议当次届满前一个月向对方书面提出异议。 + 甲乙双方过往签订的协议如与本协议有冲突以本协议为准。 +
+
2. + 本协议未尽事宜,双方可另行协商签订补充协议,本协议附件及补充协议是本协议不可分割的组成部分。 +
+ +
3. + 本协议附件包括《银行卡支付业务服务条款》、《拉卡拉扫码支付业务条款》、《境外银行卡支付业务条款》、《互联网支付服务条款》及其子附件(《代付服务基本条款》、《互联网快捷支付服务基本条款》、 + 《网银B2C/B2B支付服务基本条款》、《协议支付服务基本条款》、《第三方支付服务基本条款》)、《拉卡拉用户隐私政策》,上述附件由甲方登陆拉卡拉官方网站(www.lakala.com)查阅、下载并留存。 + 上述附件内容与本协议约定冲突的,以本协议约定为准。 +
+
4. + 本协议中,乙方遵照监管规范,按照最少必要原则收集、使用甲方的金融信息,用以向甲方提供服务、保障服务质量、保障甲方的账户和资金安全以及符合国家法律法规及监管规定要求,如果不同意,可能会影响服务的开通和部分服务的使用。 + 更多关于用户金融信息保护的内容,请查阅《拉卡拉用户隐私政策》 +
+
+
+
+
+ 甲方声明:乙方已采取合理方式提请甲方注意本协议、附件及官方网站公示内容的条款,并详细说明;甲方在本协议上签字视为同意本协议、附件及官方网站公示内容的条款。 +
+
+
+
+
+
+
+
拉卡拉商户注册登记表
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
执照信息
营业执照号 + ${licenseNo} 法人 + ${legalName}
执照名/商户名${licenseName}身份证号${identityNo}
所在区域${address}有效期${identityNoExpire}
详细地址${receiveDetail}
结算信息
入账户名${accountName}身份证号${accountIdCard}
入款账号${accountNo}有效期${accountIdDtEnd}
开户行${bankName}
商户信息
签购单名称${licenseName}对账单邮箱${mail}
联系人${contactManName}商户类别${channelType}
手机号${phone}商户地址${receiveDetail}
数据处理方${agencyName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_agent.ftl b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_agent.ftl new file mode 100644 index 0000000..40845d4 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_agent.ftl @@ -0,0 +1,64 @@ +server +{ + listen 443 ssl; + server_name ${agentSiteUrl}; + index index.php index.html index.htm default.php default.htm default.html; + root /www/wwwroot/p.server/dist; + try_files $uri $uri/ /index.html; + + #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则 + #error_page 404/404.html; + ssl_certificate ${agentSiteCrtPath}; + ssl_certificate_key ${agentSitePriKeyPath}; + #SSL-END + + #ERROR-PAGE-START 错误页配置,可以注释、删除或修改 + #error_page 404 /404.html; + #error_page 502 /502.html; + #ERROR-PAGE-END + + #禁止访问的文件或目录 + location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) + { + return 404; + } + + #一键申请SSL证书验证目录相关设置 + location ~ \.well-known{ + allow all; + } + + #禁止在证书验证目录放入敏感文件 + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ + { + expires 30d; + error_log /dev/null; + access_log /dev/null; + } + + location ~ .*\.(js|css)?$ + { + expires 12h; + error_log /dev/null; + access_log /dev/null; + } + + location /api/ + { + proxy_next_upstream http_502 http_504 error timeout invalid_header; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://agent-api; + # 启用支持websocket连接 + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + access_log /www/wwwlogs/${agentSiteUrl}.log; + error_log /www/wwwlogs/${agentSiteUrl}.error.log; +} diff --git a/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_mch.ftl b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_mch.ftl new file mode 100644 index 0000000..4287a54 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/main/resources/templates/nginx_mch.ftl @@ -0,0 +1,64 @@ +server +{ + listen 443 ssl; + server_name ${agentSiteUrl}; + index index.php index.html index.htm default.php default.htm default.html; + root /www/wwwroot/b.server/dist; + try_files $uri $uri/ /index.html; + + #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则 + #error_page 404/404.html; + ssl_certificate ${agentSiteCrtPath}; + ssl_certificate_key ${agentSitePriKeyPath}; + #SSL-END + + #ERROR-PAGE-START 错误页配置,可以注释、删除或修改 + #error_page 404 /404.html; + #error_page 502 /502.html; + #ERROR-PAGE-END + + #禁止访问的文件或目录 + location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) + { + return 404; + } + + #一键申请SSL证书验证目录相关设置 + location ~ \.well-known{ + allow all; + } + + #禁止在证书验证目录放入敏感文件 + if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { + return 403; + } + + location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ + { + expires 30d; + error_log /dev/null; + access_log /dev/null; + } + + location ~ .*\.(js|css)?$ + { + expires 12h; + error_log /dev/null; + access_log /dev/null; + } + + location /api/ + { + proxy_next_upstream http_502 http_504 error timeout invalid_header; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://merchant-api; + # 启用支持websocket连接 + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + access_log /www/wwwlogs/${agentSiteUrl}.log; + error_log /www/wwwlogs/${agentSiteUrl}.error.log; +} diff --git a/jeepay-components/jeepay-components-3rd/src/test/java/.gitkeep b/jeepay-components/jeepay-components-3rd/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-3rd/src/test/java/reconciliation/BillTestData.java b/jeepay-components/jeepay-components-3rd/src/test/java/reconciliation/BillTestData.java new file mode 100644 index 0000000..63b1a69 --- /dev/null +++ b/jeepay-components/jeepay-components-3rd/src/test/java/reconciliation/BillTestData.java @@ -0,0 +1,136 @@ +package reconciliation; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/*** +* jeepay-plus 生成对账测试数据 +* +* @author zx +* +* @date 2022/9/16 10:38 +*/ +public class BillTestData { + + static String ISV_NO = "V1648691605"; + static String MCH_NO = "M1648693513"; + static String MCH_APPID = "62451114500860516e34305c"; + static String IF_CODE = "shengpay"; + static String CHANNEL_MCH_NO = "39301087"; + + public static void main(String[] args) throws Exception { + + // 订单sql集合 + List sqlList = new ArrayList<>(); + + // 渠道账单集合 + List channelBillList = new ArrayList<>(); + + Date billDate = DateUtil.beginOfDay(DateUtil.yesterday()); + + String payOrderSqlModel = "INSERT INTO t_pay_order VALUES ('%s', '%s', '%s', NULL, NULL, '%s', '笑果', 2, 1001, '[默认]笑果', NULL, NULL, NULL, NULL, " + + "'%s', '%s', 'WX_BAR', 'WECHAT', %d, '单笔费率:0.50', %d, 'CNY', %d, 1, '0:0:0:0:0:0:0:1', '接口调试[M1648693513商户联调]', '接口调试[M1648693513商户联调]', " + + "NULL, 'ooIeqsynvcGLKQTomxRRX1plvSj4', " + + "'%s', NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 'http://192.168.0.113:9218/api/anon/paytestNotify/payOrder', NULL, NULL, NULL, 100034, " + + "'2022-09-16 13:11:28', '2022-5-13 11:11:30', '%s', '%s')"; + + Long feeAmount = 0L; + + // 平账数据 + for (int i = 1; i <= 10000; i++) { + + // 替换顺序:支付订单号,商户号,服务商号,商户应用appId,商户订单号,支付接口ifCode,订单金额,支付状态,渠道订单号 + sqlList.add(String.format(payOrderSqlModel, "PPPPPPPPPPPPPPPP" + i, MCH_NO, ISV_NO, MCH_APPID, "MMMMMMMMMMMMMMMM" + i, + IF_CODE, i, feeAmount, 2, "CCCCCCCCCCCCCCCC" + i, DateUtil.formatDateTime(billDate), DateUtil.formatDateTime(billDate))); + + JSONObject bill = new JSONObject(); + bill.put("billType", "pay"); // pay:支付, refund:退款 + bill.put("ifCode", IF_CODE); // 支付接口代码 + bill.put("channelMchNo", CHANNEL_MCH_NO); // 渠道商户号 + bill.put("billDate", billDate); // 对账日期 + bill.put("orderId", "PPPPPPPPPPPPPPPP" + i); // 渠道商户订单号 + bill.put("channelAmount", i); // 交易金额,单位分 + bill.put("channelFeeAmount", 0); // 渠道手续费,单位分 + bill.put("channelOrderNo", "CCCCCCCCCCCCCCCC" + i); // 渠道订单号 + bill.put("channelState", 2); + bill.put("channelSuccessAt", "2022-09-16 13:11:28"); + channelBillList.add(bill); + } + + // 本地多帐类型 + // for (int i = 20001; i <= 20055; i++) { + // sqlList.add(String.format(payOrderSqlModel, "PPPPPPPPPPPPPPPP" + i, MCH_NO, ISV_NO, MCH_APPID, "MMMMMMMMMMMMMMMM" + i, + // IF_CODE, i, feeAmount, 2, "CCCCCCCCCCCCCCCC" + i, DateUtil.formatDateTime(billDate), DateUtil.formatDateTime(billDate))); + // } + + // 渠道多帐类型 + // for (int i = 30001; i <= 30088; i++) { + // JSONObject bill = new JSONObject(); + // bill.put("billType", "pay"); // pay:支付, refund:退款 + // bill.put("ifCode", IF_CODE); // 支付接口代码 + // bill.put("channelMchNo", CHANNEL_MCH_NO); // 渠道商户号 + // bill.put("billDate", billDate); // 对账日期 + // bill.put("orderId", "PPPPPPPPPPPPPPPP" + i); // 渠道商户订单号 + // bill.put("channelAmount", i); // 交易金额,单位分 + // bill.put("channelFeeAmount", 0); // 渠道手续费,单位分 + // bill.put("channelOrderNo", "CCCCCCCCCCCCCCCC" + i); // 渠道订单号 + // bill.put("channelState", 2); + // bill.put("channelSuccessAt", "2022-09-16 13:11:28"); + // channelBillList.add(bill); + // } + + // 金额不一致 + for (int i = 0; i < channelBillList.size(); i++) { + JSONObject jsonObject = channelBillList.get(i); + if (jsonObject.getLong("channelAmount") <= 27) { + jsonObject.put("channelAmount", i * 2); + } + } + + + String projectPath = System.getProperty("user.dir"); //获取当前项目的 文件夹地址 + String resourcePath = projectPath + File.separator+ "jeepay-components/jeepay-components-3rd/src/main/resources/channel/shengpay/"; + + File sqlFile = new File(resourcePath + "pay_order.sql"); + File billFile = new File(resourcePath + "bill.json"); + + + // 写入文件 + writeFile(sqlFile, "UTF-8", CollUtil.join(sqlList, ";\n")); + writeFile(billFile, "UTF-8", JSON.toJSONString(channelBillList, false)); + + System.out.println("完成! "); + + } + + /** 将指定内容写入 到对应的文件中 **/ + public static void writeFile(File needWriteFile, String charset, String writeText) throws Exception { + + FileOutputStream fos = new FileOutputStream(needWriteFile); + OutputStreamWriter osw = new OutputStreamWriter(fos, charset); + BufferedWriter writer = new BufferedWriter (osw); + + try { + writer.write(writeText); + writer.flush(); + + }catch (Exception e){ + throw e; + }finally { + if(writer != null) writer.close(); + if(osw != null) writer.close(); + if(fos != null) writer.close(); + } + } + +} diff --git a/jeepay-components/jeepay-components-3rd/src/test/resources/.gitkeep b/jeepay-components/jeepay-components-3rd/src/test/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-bizcommons/pom.xml b/jeepay-components/jeepay-components-bizcommons/pom.xml new file mode 100644 index 0000000..69aa226 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + com.jeequan + jeepay-components-bizcommons + jar + ${isys.version} + Jeepay计全支付系统 [jeepay-components-oss] + https://www.jeequan.com + + + com.jeequan + jeepay-components + Final + + + + + ${basedir}/../../ + + + + + + + + com.jeequan + jeepay-components-db + + + + + com.jeequan + jeepay-components-oss + + + + + org.springframework + spring-webmvc + provided + + + + + org.slf4j + slf4j-api + + + + + org.springframework.boot + spring-boot + provided + + + + org.springframework.boot + spring-boot-autoconfigure + provided + + + + javax.annotation + javax.annotation-api + provided + + + + + com.aliyun.oss + aliyun-sdk-oss + compile + + + + javax.servlet + javax.servlet-api + provided + + + + + org.springframework.security + spring-security-core + provided + + + + + com.google.zxing + core + provided + + + com.google.zxing + javase + provided + + + + + + + + src/main/resources + + + src/main/java + **/*.xml + + + + + + diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchPayPassageConfigManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchPayPassageConfigManage.java new file mode 100644 index 0000000..452c435 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchPayPassageConfigManage.java @@ -0,0 +1,157 @@ +package com.jeequan.jeepay.bizcommons.manage; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +/** + * 商户通道配置信息 + * + * @author terrfly + * @date 2022/3/30 16:27 + */ +@Component +public class MchPayPassageConfigManage { + + @Autowired + private MchPayPassageService mchPayPassageService; + @Autowired + private PayWayService payWayService; + @Autowired + private MchInfoService mchInfoService; + @Autowired + private MchAppService mchAppService; + @Autowired + private RateConfigService rateConfigService; + @Autowired + private PayInterfaceConfigService payInterfaceConfigService; + @Autowired + private PayInterfaceDefineService payInterfaceDefineService; + + /** + * 支付方式 <--> 通道配置 + * 左侧列表(支付方式) + **/ + public ApiRes queryPaywayList(String appId, String wayCode, String wayName, String wayType, String unionSearchId, IPage page) { + + //支付方式集合 + LambdaQueryWrapper wrapper = PayWay.gw(); + wrapper.eq(StrUtil.isNotBlank(wayType), PayWay::getWayType, wayType); + wrapper.eq(StrUtil.isNotBlank(wayCode), PayWay::getWayCode, wayCode); + wrapper.like(StrUtil.isNotBlank(wayName), PayWay::getWayName, wayName); + + // app模糊搜索 + if (StringUtils.isNotBlank(unionSearchId)) { + wrapper.and(i -> { + i.like(PayWay::getWayCode, unionSearchId) + .or().like(PayWay::getWayName, unionSearchId); + }); + } + + // 查询分页数据 + IPage result = payWayService.page(page, wrapper); + + // 无数据 + if (result.getRecords().isEmpty()) { + return ApiRes.page(result); + } + + // 全部的支付方式 + Set paywayCodeList = new HashSet<>(); + result.getRecords().stream().forEach(r -> paywayCodeList.add(r.getWayCode())); + + // 查询所有的支付方式, 当前已开通的 + Map paywayCodeStateMap = new HashMap<>(); + + // 查询当前商户已经开通的数据 + mchPayPassageService.list(MchPayPassage.gw() + .select(MchPayPassage::getWayCode, MchPayPassage::getState) + .eq(MchPayPassage::getAppId, appId) + .eq(MchPayPassage::getState, CS.YES) + .in(MchPayPassage::getWayCode, paywayCodeList)).stream().forEach(r -> { + paywayCodeStateMap.put(r.getWayCode(), CS.YES); + }); + + result.getRecords().stream().forEach(r -> { + // 是否已经配置 + r.addExt("isConfig", paywayCodeStateMap.get(r.getWayCode()) != null ? CS.YES : CS.NO); + }); + + return ApiRes.page(result); + } + + + /** + * 支付方式 <--> 通道配置 + * 右侧列表(可用的支付接口) + **/ + public ApiRes availablePayInterface(String appId, String wayCode) { + + MchAppEntity mchAppEntity = mchAppService.getById(appId); + if (mchAppEntity == null || mchAppEntity.getState() != CS.YES) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + MchInfo mchInfo = mchInfoService.getById(mchAppEntity.getMchNo()); + if (mchInfo == null || mchInfo.getState() != CS.YES) { + return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH); + } + + Set ifCodes = new HashSet<>(); + + // 查询出 商户配置过费率的支付接口 + Map rateConfigMap = new HashMap<>(); + rateConfigService.list( + RateConfig.gw() + .eq(RateConfig::getInfoId, RateConfig.appendInfoByMchApp(appId)) + .eq(RateConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .eq(RateConfig::getWayCode, wayCode) + ).stream().forEach(r -> { + rateConfigMap.put(r.getIfCode(), r); + ifCodes.add(r.getIfCode()); + }); + + if (rateConfigMap.isEmpty()) { + return ApiRes.page(new Page()); + } + + // 查询出 商户配置过 支付接口参数的 列表 + Map payInterfaceConfigMap = new HashMap<>(); + + payInterfaceConfigService.list(PayInterfaceConfig.gw().eq(PayInterfaceConfig::getInfoId, appId).eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .in(PayInterfaceConfig::getIfCode, ifCodes) + .eq(PayInterfaceConfig::getState, CS.YES) + ).stream().forEach(r -> payInterfaceConfigMap.put(r.getIfCode(), r)); + + if (payInterfaceConfigMap.isEmpty()) { + return ApiRes.page(new Page()); + } + + // 查询当前开启的配置 + MchPayPassage mchPayPassage = mchPayPassageService.findMchPayPassage(mchInfo.getMchNo(), appId, wayCode); + String currentOpenIfCode = mchPayPassage != null ? mchPayPassage.getIfCode() : ""; + + // 查询支付接口 + List result = payInterfaceDefineService.list(PayInterfaceDefine.gw().in(PayInterfaceDefine::getIfCode, ifCodes).eq(PayInterfaceDefine::getState, CS.YES)); + result.stream().forEach(r -> { + + r.addExt("configState", currentOpenIfCode.equals(r.getIfCode()) ? CS.YES : CS.NO); + r.addExt("paywayFee", rateConfigMap.get(r.getIfCode()).getPaywayFeeDetail()); + + }); + + return ApiRes.page(new Page().setRecords(result).setTotal(result.size())); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchStoreTerminalManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchStoreTerminalManage.java new file mode 100644 index 0000000..19e088c --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/MchStoreTerminalManage.java @@ -0,0 +1,236 @@ +package com.jeequan.jeepay.bizcommons.manage; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchTerminalService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.model.terminal.TerminalChannelModel; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/*** + * 终端设备管理 + * + * @author terrfly + * @date 2022/4/26 17:34 + */ +@Slf4j +@Component +public class MchStoreTerminalManage { + + @Autowired private MchStoreTerminalService mchStoreTerminalService; + @Autowired private MchInfoService mchInfoService; + @Autowired private MchStoreService mchStoreService; + @Autowired + private MchApplymentService mchApplymentService; + @Autowired private PayInterfaceDefineService payInterfaceDefineService; + @Autowired private PayInterfaceConfigService payInterfaceConfigService; + + + /** add */ + public ApiRes add(MchStoreTerminal record ) { + + if(mchStoreTerminalService.count(MchStoreTerminal.gw().eq(MchStoreTerminal::getMchNo, record.getMchNo()) + .eq(MchStoreTerminal::getStoreId, record.getStoreId()).eq(MchStoreTerminal::getTrmNo, record.getTrmNo()) + .eq(MchStoreTerminal::getAppId, record.getAppId()) + ) > 0 ){ + throw new BizException("当前设备编号已经存在!"); + } + + MchInfo mchInfo = mchInfoService.getById(record.getMchNo()); + + record.setMchName(mchInfo.getMchShortName()); + record.setAgentNo(mchInfo.getAgentNo()); + record.setStoreName(mchStoreService.getById(record.getStoreId()).getStoreName()); + + record.setChannelBindInfo(new JSONObject()); + mchStoreTerminalService.save(record); + return ApiRes.ok(); + } + + + /** update */ + public ApiRes update(MchStoreTerminal record) { + + // 不允许更改一下信息 + record.setMchNo(null); + record.setAppId(null); + record.setStoreId(null); + record.setAgentNo(null); + record.setCreatedAt(null); + record.setUpdatedAt(null); + + mchStoreTerminalService.updateById(record); + return ApiRes.ok(); + } + + + /** update */ + public ApiRes updateDefault(Long trmId, Byte updateFlag) { + + // 查询DB数据 + MchStoreTerminal dbRecord = mchStoreTerminalService.getById(trmId); + + if(dbRecord == null){ + throw new BizException("数据不存在"); + } + + MchStoreTerminal updateRecord = new MchStoreTerminal(); + updateRecord.setTrmId(dbRecord.getTrmId()); + updateRecord.setDefaultFlag(updateFlag); + + if(updateFlag == CS.NO){ + mchStoreTerminalService.updateById(updateRecord); + }else{ + + //更新所有的为 否 + mchStoreTerminalService.update(new LambdaUpdateWrapper() + .eq(MchStoreTerminal::getMchNo, dbRecord.getMchNo()) + .eq(MchStoreTerminal::getAppId, dbRecord.getAppId()) + .eq(MchStoreTerminal::getStoreId, dbRecord.getStoreId()) + .set(MchStoreTerminal::getDefaultFlag, CS.NO) + ); + + mchStoreTerminalService.updateById(updateRecord); + } + + return ApiRes.ok(); + } + + + /** 报备列表 */ + public ApiRes getChannelBindInfos(Long recordId) { + + MchStoreTerminal dbRecord = mchStoreTerminalService.getById(recordId); + + // 查询出所有的支持通道集合 + List ifCodeList = new ArrayList<>(); + payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode) + .eq(PayInterfaceConfig::getInfoType, CS.SYS_ROLE_TYPE.MCH_APP) + .eq(PayInterfaceConfig::getInfoId, dbRecord.getAppId()) + .eq(PayInterfaceConfig::getState, CS.YES) + ).forEach(r -> ifCodeList.add(r.getIfCode())); + + if(ifCodeList.isEmpty()){ + return ApiRes.ok(ifCodeList); + } + + + JSONObject channelBindInfo = dbRecord.getChannelBindInfo(); + if(channelBindInfo == null){ + channelBindInfo = new JSONObject(); + } + + // 查询出所有的应用集合 + List result = payInterfaceDefineService.list(PayInterfaceDefine.gw().in(PayInterfaceDefine::getIfCode, ifCodeList)); + for (PayInterfaceDefine payInterfaceDefine : result) { + + TerminalChannelModel model = channelBindInfo.getObject(payInterfaceDefine.getIfCode(), TerminalChannelModel.class); + + // 判断是否为空 + if(model == null || model.getState() == null){ + model = new TerminalChannelModel().setState(TerminalChannelModel.STATE_NOT_BIND); + } + + payInterfaceDefine.addExt("channelBindInfo", model); + } + + return ApiRes.ok(result); + } + + + /** 终端报备 */ + public ApiRes channelSendup(Long recordId, String ifCode, Byte state) { + + MchStoreTerminal dbRecord = mchStoreTerminalService.getById(recordId); + + JSONObject channelBindInfo = dbRecord.getChannelBindInfo(); + if(channelBindInfo == null){ + channelBindInfo = new JSONObject(); + } + + String storeId = dbRecord.getStoreId(); + MchStore mchStore = mchStoreService.getById(storeId); + String mchApplyId = mchStore.getMchApplyId(); + MchApplyment mchApplyment = mchApplymentService.getById(mchApplyId); + + // 单独接口的对象 + TerminalChannelModel ifCodeModel = channelBindInfo.getObject(ifCode, TerminalChannelModel.class); + if(ifCodeModel == null){ + ifCodeModel = new TerminalChannelModel(); + } + + IIsvmchTerminalService isvmchTerminalService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "IsvmchTerminalService", IIsvmchTerminalService.class); + if(isvmchTerminalService == null){ + ifCodeModel.setState(TerminalChannelModel.STATE_FAIL).setErrInfo(ifCode + "接口不支持报备操作"); + }else{ + ChannelRetMsg channelRetMsg = isvmchTerminalService.sendup(dbRecord, mchApplyment.getIsvNo(), dbRecord.getMchNo(), dbRecord.getAppId(), ifCode, state == CS.YES); + + // 操作成功 + if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS){ + + ifCodeModel.setErrInfo(null); + + if(state == CS.YES){ // 报备 + ifCodeModel.setChannelTrmNo(channelRetMsg.getChannelOrderId()); + }else{ // 取消报备 + ifCodeModel.setChannelTrmNo(null); + } + + ifCodeModel.setState(state); + + }else{ //操作失败 + ifCodeModel.setState(TerminalChannelModel.STATE_FAIL); + ifCodeModel.setErrInfo(channelRetMsg.getChannelErrMsg()); + } + } + + channelBindInfo.put(ifCode, ifCodeModel); + + MchStoreTerminal updateRecord = new MchStoreTerminal().setTrmId(recordId).setChannelBindInfo(channelBindInfo); + mchStoreTerminalService.updateById(updateRecord); + + return ApiRes.ok(); + } + + + /** 修改终端报备信息 */ + public ApiRes updChannelBindInfos(Long recordId, String ifCode, String channelTrmNo, Byte state) { + + + MchStoreTerminal dbRecord = mchStoreTerminalService.getById(recordId); + + JSONObject channelBindInfo = dbRecord.getChannelBindInfo(); + if(channelBindInfo == null){ + channelBindInfo = new JSONObject(); + } + + // 单独接口的对象 + TerminalChannelModel ifCodeModel = channelBindInfo.getObject(ifCode, TerminalChannelModel.class); + if(ifCodeModel == null){ + ifCodeModel = new TerminalChannelModel(); + } + + ifCodeModel.setChannelTrmNo(channelTrmNo); + ifCodeModel.setState(state); + channelBindInfo.put(ifCode, ifCodeModel); + + MchStoreTerminal updateRecord = new MchStoreTerminal().setTrmId(recordId).setChannelBindInfo(channelBindInfo); + mchStoreTerminalService.updateById(updateRecord); + + return ApiRes.ok(); + } + + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayIotDeviceBindManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayIotDeviceBindManage.java new file mode 100644 index 0000000..ba04365 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayIotDeviceBindManage.java @@ -0,0 +1,164 @@ +package com.jeequan.jeepay.bizcommons.manage.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayIotDeviceBindService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.alipay.AlipaySpOperationInfo; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchApplyment; +import com.jeequan.jeepay.db.entity.MchConfig; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchStoreDevice; +import com.jeequan.jeepay.service.impl.*; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/*** +* 支付宝Iot设备-店铺绑定ctrl +* +* @author zx +* @date 2023/03/13 15:26 +*/ +@Component +public class AlipayIotDeviceBindManage { + + @Autowired private MchInfoService mchInfoService; + @Autowired private MchStoreService mchStoreService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private MchConfigService mchConfigService; + @Autowired private IConfigContextQueryService configContextQueryService; + @Autowired + private MchApplymentService mchApplymentService; + + /** 绑定蚂蚁店铺 **/ + public ApiRes bind(String mchNo, Long deviceId, Byte alipayBindState, String bindStoreId) { + try { + if (CS.YES == alipayBindState && bindStoreId == null) { + return ApiRes.customFail("请选择要绑定的蚂蚁店铺"); + } + + // 校验&&获取绑定设备所需信息 + MutablePair pair = checkAndGetAlipaySpOperationInfo(mchNo, bindStoreId, deviceId); + MchStoreDevice mchStoreDevice = pair.getRight(); + String supplierId = MchStoreDevice.ALIPAY_IOT_DEVICE_MAP.get(mchStoreDevice.getProvider()); + + IAlipayIotDeviceBindService alipayIotDeviceBindService = SpringBeansUtil.getBean(IAlipayIotDeviceBindService.class); + + // 绑定 + if (CS.YES == alipayBindState) { + // 换绑 需先解绑 + if (mchStoreDevice.getAlipayBindState() == CS.YES) { + alipayIotDeviceBindService.unbind(pair.getLeft(), mchStoreDevice.getMchNo(), mchStoreDevice.extv().getString("alipayMerchantNo"), + mchStoreDevice.getAlipayShopId(), supplierId, mchStoreDevice.getDeviceNo()); + } + + JSONObject deviceJSON = new JSONObject(); + deviceJSON.put("deviceType", mchStoreDevice.getDeviceType()); + deviceJSON.put("deviceNo", mchStoreDevice.getDeviceNo()); + deviceJSON.put("provider", mchStoreDevice.getProvider()); + + alipayIotDeviceBindService.bind(pair.getLeft(), mchStoreDevice.getMchNo(), mchStoreDevice.extv().getString("alipayMerchantNo"), + mchStoreDevice.extv().getString("alipayShopId"), supplierId, deviceJSON); + + // 蚂蚁店铺设备绑定成功 + MchStoreDevice updateRecord = new MchStoreDevice(); + updateRecord.setDeviceId(deviceId); + updateRecord.setAlipayBindState(CS.YES); + updateRecord.setAlipayShopId(mchStoreDevice.extv().getString("alipayShopId")); + mchStoreDeviceService.updateById(updateRecord); + } + // 解绑 + else { + alipayIotDeviceBindService.unbind(pair.getLeft(), mchStoreDevice.getMchNo(), mchStoreDevice.extv().getString("alipayMerchantNo"), + mchStoreDevice.getAlipayShopId(), supplierId, mchStoreDevice.getDeviceNo()); + + // 蚂蚁店铺设备解绑成功 + MchStoreDevice updateRecord = new MchStoreDevice(); + updateRecord.setDeviceId(deviceId); + updateRecord.setAlipayBindState(CS.NO); + updateRecord.setAlipayShopId(""); + mchStoreDeviceService.updateById(updateRecord); + } + + return ApiRes.ok(); + }catch (Exception e) { + throw new BizException(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 查询设备信息 **/ + public ApiRes query(String mchNo, String storeId, Long deviceId) { + try { + MutablePair pair = checkAndGetAlipaySpOperationInfo(mchNo, storeId, deviceId); + MchStoreDevice mchStoreDevice = pair.getRight(); + + IAlipayIotDeviceBindService alipayIotDeviceBindService = SpringBeansUtil.getBean(IAlipayIotDeviceBindService.class); + JSONObject resJSON = alipayIotDeviceBindService.query(pair.getLeft(), mchStoreDevice.getDeviceNo()); + + return ApiRes.ok(resJSON); + }catch (Exception e) { + throw new BizException(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + + /** 查询当前商户支付宝授权信息 **/ + private MutablePair checkAndGetAlipaySpOperationInfo(String mchNo, String bindStoreId, Long deviceId) { + // 查询绑定设备信息 + MchStoreDevice storeDevice = mchStoreDeviceService.getById(deviceId); + if (storeDevice == null || storeDevice.getState() != CS.YES || storeDevice.getBindState() != CS.YES || storeDevice.getDeviceType() != MchStoreDevice.DEVICE_TYPE_RUYI) { + throw new BizException("设备不存在或未绑定"); + } + // 运营平台只传deviceId,商户系统传递mchNo并校验权限 + if (StringUtils.isNotBlank(mchNo) && !mchNo.equals(storeDevice.getMchNo())) { + throw new BizException(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + mchNo = StringUtils.defaultIfBlank(mchNo, storeDevice.getMchNo()); + com.jeequan.jeepay.db.entity.MchStore mchStore2 = mchStoreService.getById(storeDevice.getStoreId()); + MchApplyment mchApplyment = mchApplymentService.getById(mchStore2.getMchApplyId()); + + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (MchInfo.TYPE_ISVSUB != mchInfo.getType()) { + throw new BizException("仅支持特约商户"); + } + + AlipayIsvParams alipayIsvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchApplyment.getIsvNo(), CS.IF_CODE.ALIPAY); + if (alipayIsvParams == null) { + throw new BizException("服务商未配置参数,请联系平台处理!"); + } + + // 查询授权商户号 + MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(mchNo, AlipaySpOperationInfo.MCH_CONFIG_KEY); + if (mchConfig == null || StringUtils.isBlank(mchConfig.getConfigVal())) { + throw new BizException("请先发起支付宝代运营授权"); + } + + AlipaySpOperationInfo operationInfo = JSON.parseObject(mchConfig.getConfigVal(), AlipaySpOperationInfo.class); + if (!AlipaySpOperationInfo.HANDLE_STATUS_SUCCESS.equals(operationInfo.getHandleStatus()) || StringUtils.isBlank(operationInfo.getMerchantNo())) { + throw new BizException("请先发起支付宝代运营授权"); + } + + // 查询蚂蚁店铺ID + if (bindStoreId != null) { + com.jeequan.jeepay.db.entity.MchStore mchStore = mchStoreService.getById(bindStoreId); + if (!MchStore.ALIPAY_SHOP_STATUS_SUCCESS.equals(mchStore.getAlipayShopStatus()) || StringUtils.isBlank(mchStore.getAlipayShopId())) { + throw new BizException("当前店铺未同步至蚂蚁店铺"); + } + storeDevice.addExt("alipayShopId", mchStore.getAlipayShopId()); + } + + storeDevice.addExt("alipayMerchantNo", operationInfo.getMerchantNo()); + + return MutablePair.of(alipayIsvParams, storeDevice); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayOpenSpOperationManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayOpenSpOperationManage.java new file mode 100644 index 0000000..7052220 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayOpenSpOperationManage.java @@ -0,0 +1,162 @@ +package com.jeequan.jeepay.bizcommons.manage.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayOpenSpOperationService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.alipay.AlipaySpOperationInfo; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchConfig; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchStore; +import com.jeequan.jeepay.db.entity.MchStoreDevice; +import com.jeequan.jeepay.service.impl.MchConfigService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.MchStoreDeviceService; +import com.jeequan.jeepay.service.impl.MchStoreService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +/*** +* 支付宝服务商代运营授权 +* +* @author zx +* @date 2023/03/13 15:26 +*/ +@Component +public class AlipayOpenSpOperationManage { + + @Autowired private MchInfoService mchInfoService; + @Autowired private MchConfigService mchConfigService; + @Autowired private MchStoreService mchStoreService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private IConfigContextQueryService configContextQueryService; + + /** 获取授权码 **/ + public ApiRes queryQrcode(String mchNo, String alipayAccount) { + try { + AlipayIsvParams alipayIsvParams = applyCheck(mchNo); + + IAlipayOpenSpOperationService alipayOpenSpOperationService = SpringBeansUtil.getBean(IAlipayOpenSpOperationService.class); + JSONObject resJSON = alipayOpenSpOperationService.querySpOperationQrcode(alipayIsvParams, alipayAccount); + + // 保存或更新发起授权的支付宝登录账号 + mchInfoService.saveOrUpdateAlipaySpOperationAccount(mchNo, alipayAccount, "qrcode"); + + return ApiRes.ok(resJSON); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 发起授权 **/ + public ApiRes apply(String mchNo, String alipayAccount) { + try { + AlipayIsvParams alipayIsvParams = applyCheck(mchNo); + + IAlipayOpenSpOperationService alipayOpenSpOperationService = SpringBeansUtil.getBean(IAlipayOpenSpOperationService.class); + JSONObject resJSON = alipayOpenSpOperationService.applySpOperation(alipayIsvParams, alipayAccount); + + // 保存或更新发起授权的支付宝登录账号 + mchInfoService.saveOrUpdateAlipaySpOperationAccount(mchNo, alipayAccount, "apply"); + + return ApiRes.ok(resJSON); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 查询支付宝授权结果 **/ + public ApiRes queryResult(String mchNo) { + try { + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (MchInfo.TYPE_ISVSUB != mchInfo.getType()) { + throw new BizException("仅支持特约商户"); + } + AlipayIsvParams alipayIsvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchInfo.getIsvNo(), CS.IF_CODE.ALIPAY); + if (alipayIsvParams == null) { + throw new BizException("服务商未配置参数,请联系平台处理!"); + } + + MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(mchNo, AlipaySpOperationInfo.MCH_CONFIG_KEY); + if (mchConfig == null || StringUtils.isBlank(mchConfig.getConfigVal())) { + throw new BizException("请先发起授权"); + } + AlipaySpOperationInfo dbOperationInfo = JSON.parseObject(mchConfig.getConfigVal(), AlipaySpOperationInfo.class); + if (AlipaySpOperationInfo.HANDLE_STATUS_SUCCESS.equals(dbOperationInfo.getHandleStatus())) { + throw new BizException("已授权成功,无需再次查询"); + } + + // 查询支付宝授权状态 + IAlipayOpenSpOperationService alipayOpenSpOperationService = SpringBeansUtil.getBean(IAlipayOpenSpOperationService.class); + AlipaySpOperationInfo operationResult = alipayOpenSpOperationService.querySpOperationResult(alipayIsvParams, dbOperationInfo.getAlipayAccount()); + + // 更新授权状态 + if (AlipaySpOperationInfo.HANDLE_STATUS_SUCCESS.equals(operationResult.getHandleStatus())) { + dbOperationInfo.setHandleStatus(operationResult.getHandleStatus()); + dbOperationInfo.setMerchantNo(operationResult.getMerchantNo()); + + MchConfig updateRecord = new MchConfig(); + updateRecord.setConfigVal(JSON.toJSONString(dbOperationInfo)); + mchConfigService.update(updateRecord, + new LambdaUpdateWrapper().eq(MchConfig::getConfigKey, AlipaySpOperationInfo.MCH_CONFIG_KEY).eq(MchConfig::getMchNo, mchNo)); + } + + return ApiRes.ok(operationResult); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 查询当前商户支付宝授权信息 **/ + public ApiRes authInfo(String mchNo) { + MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(mchNo, AlipaySpOperationInfo.MCH_CONFIG_KEY); + if (mchConfig == null || StringUtils.isBlank(mchConfig.getConfigVal())) { + return ApiRes.ok(); + } + + return ApiRes.ok(JSON.parseObject(mchConfig.getConfigVal())); + } + + + private AlipayIsvParams applyCheck(String mchNo) { + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (MchInfo.TYPE_ISVSUB != mchInfo.getType()) { + throw new BizException("仅支持特约商户"); + } + + AlipayIsvParams alipayIsvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchInfo.getIsvNo(), CS.IF_CODE.ALIPAY); + if (alipayIsvParams == null) { + throw new BizException("服务商未配置参数,请联系平台处理!"); + } + + // 查询是否存在绑定的设备 + long count = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getMchNo, mchNo) + .eq(MchStoreDevice::getDeviceType, MchStoreDevice.DEVICE_TYPE_RUYI) + .eq(MchStoreDevice::getAlipayBindState, CS.YES) + ); + if (count > 0) { + throw new BizException("存在绑定的如意设备,请先将如意设备从蚂蚁店铺解绑!"); + } + + // 查询是否存在绑定蚂蚁店铺 + count = mchStoreService.count(MchStore.gw(). + eq(MchStore::getMchNo, mchNo) + .in(MchStore::getAlipayShopStatus, Arrays.asList(MchStore.ALIPAY_SHOP_STATUS_SUCCESS, MchStore.ALIPAY_SHOP_STATUS_AUDITING)) + ); + if (count > 0) { + throw new BizException("已创建蚂蚁店铺,请先关闭蚂蚁店铺!"); + } + return alipayIsvParams; + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayShopManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayShopManage.java new file mode 100644 index 0000000..63e0be1 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/alipay/AlipayShopManage.java @@ -0,0 +1,215 @@ +package com.jeequan.jeepay.bizcommons.manage.alipay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService; +import com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz.IAlipayShopService; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.alipay.AlipaySpOperationInfo; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.entity.MchConfig; +import com.jeequan.jeepay.db.entity.MchInfo; +import com.jeequan.jeepay.db.entity.MchStoreDevice; +import com.jeequan.jeepay.service.impl.MchConfigService; +import com.jeequan.jeepay.service.impl.MchInfoService; +import com.jeequan.jeepay.service.impl.MchStoreDeviceService; +import com.jeequan.jeepay.service.impl.MchStoreService; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/*** +* 蚂蚁门店 +* +* @author zx +* @date 2023/03/13 15:26 +*/ +@Component +public class AlipayShopManage { + + @Autowired private MchInfoService mchInfoService; + @Autowired private MchStoreService mchStoreService; + @Autowired private MchConfigService mchConfigService; + @Autowired private MchStoreDeviceService mchStoreDeviceService; + @Autowired private IConfigContextQueryService configContextQueryService; + + /** 查询店铺详情 **/ + public ApiRes query(String mchNo, String storeId) { + try { + MutablePair mutablePair = checkAndGetAlipaySpOperationInfo(mchNo, storeId); + + IAlipayShopService alipayShopService = SpringBeansUtil.getBean(IAlipayShopService.class); + MchStore result = alipayShopService.query(mutablePair.getLeft(), String.valueOf(storeId), mutablePair.getRight().getMerchantNo()); + + MchStore dbRecord = mchStoreService.getById(storeId); + result.setStoreId(storeId); + result.setAlipayShopStatus(dbRecord.getAlipayShopStatus()); + + return ApiRes.ok(result); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 创建店铺 **/ + public ApiRes create(String mchNo, String storeId, MchStore mchStore) { + try { + MutablePair mutablePair = checkAndGetAlipaySpOperationInfo(mchNo, storeId); + + IAlipayShopService alipayShopService = SpringBeansUtil.getBean(IAlipayShopService.class); + MchStore result = alipayShopService.create(mutablePair.getLeft(), mchStore, mutablePair.getRight().getMerchantNo()); + + // 蚂蚁店铺申请创建成功,保存申请单号,用于查询申请状态 + com.jeequan.jeepay.db.entity.MchStore updateRecord = new com.jeequan.jeepay.db.entity.MchStore(); + updateRecord.setStoreId(storeId); + updateRecord.setAlipayShopCreateId(result.getAlipayShopCreateId()); + updateRecord.setAlipayShopStatus(MchStore.ALIPAY_SHOP_STATUS_AUDITING); // 审核中 + mchStoreService.updateById(updateRecord); + + return ApiRes.ok(); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 修改店铺 **/ + public ApiRes update(String mchNo, String storeId, MchStore mchStore) { + try { + // 查询商户门店是否已成功创建蚂蚁店铺 + com.jeequan.jeepay.db.entity.MchStore dbRecord = mchStoreService.getById(storeId); + if (dbRecord == null || !MchStore.ALIPAY_SHOP_STATUS_SUCCESS.equals(dbRecord.getAlipayShopStatus()) || StringUtils.isBlank(dbRecord.getAlipayShopId())) { + throw new BizException("门店不存在或未成功创建蚂蚁店铺!"); + } + mchStore.setAlipayShopId(dbRecord.getAlipayShopId()); // 蚂蚁店铺ID + + MutablePair mutablePair = checkAndGetAlipaySpOperationInfo(mchNo, storeId); + + IAlipayShopService alipayShopService = SpringBeansUtil.getBean(IAlipayShopService.class); + MchStore result = alipayShopService.update(mutablePair.getLeft(), mchStore); + + // 蚂蚁店铺申请创建成功,保存申请单号,用于查询申请状态 + com.jeequan.jeepay.db.entity.MchStore updateRecord = new com.jeequan.jeepay.db.entity.MchStore(); + updateRecord.setStoreId(storeId); + updateRecord.setAlipayShopCreateId(result.getAlipayShopCreateId()); + updateRecord.setAlipayShopStatus(MchStore.ALIPAY_SHOP_STATUS_AUDITING); // 审核中 + mchStoreService.updateById(updateRecord); + + return ApiRes.ok(updateRecord); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + /** 关闭店铺 **/ + public ApiRes close(String mchNo, String storeId) { + try { + MutablePair mutablePair = checkAndGetAlipaySpOperationInfo(mchNo, storeId); + + // 查询商户门店是否已成功创建蚂蚁店铺 + com.jeequan.jeepay.db.entity.MchStore dbRecord = mchStoreService.getById(storeId); + if (dbRecord == null || !MchStore.ALIPAY_SHOP_STATUS_SUCCESS.equals(dbRecord.getAlipayShopStatus()) || StringUtils.isBlank(dbRecord.getAlipayShopId())) { + throw new BizException("门店不存在或未成功创建蚂蚁店铺!"); + } + + // 查询门店下是否绑定了设备 + long count = mchStoreDeviceService.count(MchStoreDevice.gw() + .eq(MchStoreDevice::getAlipayBindState, CS.YES) + .eq(MchStoreDevice::getAlipayShopId, dbRecord.getAlipayShopId())); + if (count > 0) { + throw new BizException("当前门店下存在绑定的设备,请先解绑"); + } + + IAlipayShopService alipayShopService = SpringBeansUtil.getBean(IAlipayShopService.class); + alipayShopService.close(mutablePair.getLeft(), dbRecord.getAlipayShopId()); + + // 蚂蚁店铺关闭成功,将本地蚂蚁门店信息改为初始未创建状态 + com.jeequan.jeepay.db.entity.MchStore updateRecord = new com.jeequan.jeepay.db.entity.MchStore(); + updateRecord.setStoreId(storeId); + updateRecord.setAlipayShopId(""); + updateRecord.setAlipayShopCreateId(""); + updateRecord.setAlipayShopStatus(MchStore.ALIPAY_SHOP_STATUS_NOT_EXISTS); // 未创建 + mchStoreService.updateById(updateRecord); + + return ApiRes.ok(); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + + /** 根据申请单查询店铺创建结果 **/ + public ApiRes createResultQuery(String mchNo, String storeId) { + try { + // 查询商户门店下 蚂蚁店铺是否为审核中 + com.jeequan.jeepay.db.entity.MchStore dbRecord = mchStoreService.getById(storeId); + if (dbRecord == null) { + throw new BizException("门店不存在!"); + } + if (MchStore.ALIPAY_SHOP_STATUS_SUCCESS.equals(dbRecord.getAlipayShopStatus())) { + return ApiRes.ok(dbRecord); + } + if (StringUtils.isBlank(dbRecord.getAlipayShopCreateId())) { + throw new BizException("未发起创建蚂蚁店铺!"); + } + + MutablePair mutablePair = checkAndGetAlipaySpOperationInfo(mchNo, storeId); + + IAlipayShopService alipayShopService = SpringBeansUtil.getBean(IAlipayShopService.class); + MchStore result = alipayShopService.createResultQuery(mutablePair.getLeft(), dbRecord.getAlipayShopCreateId()); + + // 更新蚂蚁店铺授权状态 + com.jeequan.jeepay.db.entity.MchStore updateRecord = new com.jeequan.jeepay.db.entity.MchStore(); + updateRecord.setStoreId(storeId); + updateRecord.setAlipayShopId(result.getAlipayShopId()); + updateRecord.setAlipayShopStatus(result.getAlipayShopStatus()); + mchStoreService.updateById(updateRecord); + + return ApiRes.ok(updateRecord); + }catch (Exception e) { + return ApiRes.customFail(StringUtils.defaultString(e.getMessage(), "系统异常!")); + } + } + + + /** 查询当前商户支付宝授权信息 **/ + private MutablePair checkAndGetAlipaySpOperationInfo(String mchNo, String storeId) { + MchStore mchStore = mchStoreService.getById(storeId); + if (mchStore == null) { + throw new BizException("门店不存在"); + } + // 运营平台只传storeId,商户系统传递mchNo并校验权限 + if (StringUtils.isNotBlank(mchNo) && !mchNo.equals(mchStore.getMchNo())) { + throw new BizException(ApiCodeEnum.SYS_PERMISSION_ERROR); + } + mchNo = StringUtils.defaultIfBlank(mchNo, mchStore.getMchNo()); + + MchInfo mchInfo = mchInfoService.getById(mchNo); + if (MchInfo.TYPE_ISVSUB != mchInfo.getType()) { + throw new BizException("仅支持特约商户"); + } + + AlipayIsvParams alipayIsvParams = (AlipayIsvParams) configContextQueryService.queryIsvParams(mchInfo.getIsvNo(), CS.IF_CODE.ALIPAY); + if (alipayIsvParams == null) { + throw new BizException("服务商未配置参数,请联系平台处理!"); + } + + // 查询授权商户号 + MchConfig mchConfig = mchConfigService.getByMchNoAndConfigKey(mchNo, AlipaySpOperationInfo.MCH_CONFIG_KEY); + if (mchConfig == null || StringUtils.isBlank(mchConfig.getConfigVal())) { + throw new BizException("请先发起授权"); + } + + AlipaySpOperationInfo operationInfo = JSONObject.parseObject(mchConfig.getConfigVal(), AlipaySpOperationInfo.class); + if (!AlipaySpOperationInfo.HANDLE_STATUS_SUCCESS.equals(operationInfo.getHandleStatus()) || StringUtils.isBlank(operationInfo.getMerchantNo())) { + throw new BizException("支付宝代运营授权未通过,无法操作蚂蚁店铺"); + } + + return MutablePair.of(alipayIsvParams, operationInfo); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthByQrcodeManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthByQrcodeManage.java new file mode 100644 index 0000000..91e0b93 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthByQrcodeManage.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.bizcommons.manage.auth; + +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/*** + * 扫码登录 + * + * @author zx + * @date 2022/5/17 10:34 + */ +@Slf4j +@Component +public class AuthByQrcodeManage { + + public final static String QRCODE_STATUS_WAITING = "waiting"; // 等待扫码 + public final static String QRCODE_STATUS_SCANED = "scaned"; // 已扫码 + public final static String QRCODE_STATUS_EXPRIED = "expried"; // 过期 + public final static String QRCODE_STATUS_CONFIRMED = "confirmed"; // 确认登录 + public final static String QRCODE_STATUS_CANCELED = "canceled"; // 取消登录 + + // 设置web端二维码被扫状态,等待扫码 + public static void setQrcodeStatusWaiting(String qrcodeNo) { + RedisUtil.setString(qrcodeNo, AuthByQrcodeManage.QRCODE_STATUS_WAITING, 60, TimeUnit.SECONDS); + } + + // 清空web端二维码被扫状态 + public static void delQrcodeStatus(String qrcodeNo) { + RedisUtil.del(qrcodeNo); + } + + // 更新web端二维码被扫状态为:等待扫码 --> 已扫 + public static void updateQrcodeStatusWaiting2Scaned(String qrcodeNo) { + + String qrCodeStatus = RedisUtil.getString(qrcodeNo); + if (StringUtils.isBlank(qrCodeStatus) || !qrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_WAITING)) { + throw new BizException("二维码无效,请刷新二维码后重新扫描"); + } + + RedisUtil.setString(qrcodeNo, AuthByQrcodeManage.QRCODE_STATUS_SCANED, 60, TimeUnit.SECONDS); + } + + // 更新web端二维码被扫状态,已扫 --> 确认登录 + public static void updateQrcodeStatusScaned2Confirmed(String qrcodeNo, String tokenStr) { + + String dbQrCodeStatus = RedisUtil.getString(qrcodeNo); + if (StringUtils.isBlank(dbQrCodeStatus) || !dbQrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_SCANED)) { + throw new BizException("二维码无效,请刷新二维码后重新扫描"); + } + + RedisUtil.setString(qrcodeNo, AuthByQrcodeManage.QRCODE_STATUS_CONFIRMED + "_" + tokenStr); + } + + // 更新web端二维码被扫状态,已扫 --> 取消扫码登录 + public static void updateQrcodeStatusScaned2Canceled(String sysType, String qrcodeNo) { + + String dbQrCodeStatus = RedisUtil.getString(qrcodeNo); + if (StringUtils.isBlank(dbQrCodeStatus) || !dbQrCodeStatus.equals(AuthByQrcodeManage.QRCODE_STATUS_SCANED)) { + throw new BizException("二维码无效,请刷新二维码后重新扫描"); + } + + RedisUtil.setString(qrcodeNo, AuthByQrcodeManage.QRCODE_STATUS_CANCELED); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthManage.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthManage.java new file mode 100644 index 0000000..7a090a4 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/auth/AuthManage.java @@ -0,0 +1,127 @@ +package com.jeequan.jeepay.bizcommons.manage.auth; + +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.DBsecurityConfig; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.db.entity.AgentInfo; +import com.jeequan.jeepay.service.impl.SysConfigService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/*** + * 登录校验管理 + * + * @author zx + * @date 2022/5/17 10:34 + */ +@Slf4j +@Component +public class AuthManage { + + @Autowired private SysConfigService sysConfigService; + + /** 防穷举验证 **/ + public void loginErrValidate(String sysType, String username) { + + DBsecurityConfig dbSecurityConfig = sysConfigService.getDBSecurityConfig(); + if (dbSecurityConfig.getLoginErrorMaxLimit().getErrMax() == 0) { + return; + } + + String failPassCacheKey = CS.getCacheKeyLoginErr(sysType, username); + String failCount = RedisUtil.getString(failPassCacheKey); +// if(StringUtils.isNotEmpty(failCount) && Integer.parseInt(failCount) >= dbSecurityConfig.getLoginErrorMaxLimit().getErrMax()){ //已经 临时锁定 +// throw new BizException("密码输入错误次数超限,请稍后再试"); +// } + } + + /** 防穷举累加 还可尝试x次,失败将锁定x分账 **/ + public void loginErrCount(String sysType, String username) { + + DBsecurityConfig dbSecurityConfig = sysConfigService.getDBSecurityConfig(); + if (dbSecurityConfig.getLoginErrorMaxLimit().getErrMax() == 0) { + throw new BizException("用户名/密码错误"); + } + + String failPassCacheKey = CS.getCacheKeyLoginErr(sysType, username); + + //累加缓存统计数据 + long failCountL = RedisUtil.increment(failPassCacheKey, 1); + RedisUtil.expire(failPassCacheKey, dbSecurityConfig.getLoginErrorMaxLimit().getLimitMinute(), TimeUnit.MINUTES); //缓存x分钟 + + if(failCountL >= dbSecurityConfig.getLoginErrorMaxLimit().getErrMax()){ //超过xx次 + throw new BizException("密码输入错误次数超限,请稍后再试"); + }else{ + throw new BizException("用户名/密码错误,还可尝试" + ( dbSecurityConfig.getLoginErrorMaxLimit().getErrMax() - failCountL ) + "次,失败将锁定" + + dbSecurityConfig.getLoginErrorMaxLimit().getLimitMinute() + "分钟"); + } + } + + + /** 密码过期的过滤器, 返回: true: 已过期,请直接return, false,正常请求 */ + public static boolean passwordExpiredFilter(JeeUserDetails jeeUserDetails, HttpServletRequest request, HttpServletResponse response) throws IOException { + + // 系统不强制更改 + if(!SysConfigService.PWD_EXPIRED_MUST_RESET){ + return false; + } + + // 如果密码认证 && 密码已过期 + if( JWTPayload.CREDENTIAL_AUTH_TYPE.PASSWD.equals(jeeUserDetails.getAuthType()) && + jeeUserDetails.getSysUser().getPwdExpiredTime() != null && jeeUserDetails.getSysUser().getPwdExpiredTime().compareTo(new Date()) <= 0) { + + String requestURI = request.getRequestURI(); + + // 查询用户信息 修改密码,可操作 + if(requestURI.indexOf("/api/current/user") >= 0 || requestURI.indexOf("/api/current/modifyPwd") >= 0){ + return false; + } + + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + response.getWriter().println(ApiRes.fail(ApiCodeEnum.SYS_USER_PWD_EXPIRED).toJSONString()); + response.getWriter().flush(); + return true; + } + + return false; + } + + /** 服务商未审核过滤器, 返回: true: 未过审,请直接return, false,正常请求 */ + public static boolean agentUnAuditFilter(JeeUserDetails jeeUserDetails, HttpServletRequest request, HttpServletResponse response) throws IOException { + + // 如果当前服务商状态为待审核/审核驳回 跳转至资料 + if(jeeUserDetails.getInfoState() == AgentInfo.AUDIT_STATE_ING || jeeUserDetails.getInfoState() == AgentInfo.AUDIT_STATE_FALSE + || jeeUserDetails.getInfoState() == AgentInfo.AUDIT_STATE_UN_AUTH) { + + String requestURI = request.getRequestURI(); + + // 查询用户信息、退出登录、修改密码、文件上传、信息修改->可操作 + if(requestURI.indexOf("/api/current/user") >= 0 || requestURI.indexOf("/api/current/logout") >= 0 ||requestURI.indexOf("/api/mainChart") >= 0 + || requestURI.indexOf("/api/ossFiles/form") >= 0 || requestURI.indexOf("/api/ossFiles/singleFile") >= 0 || requestURI.indexOf("/api/sysUsers/audit") >= 0){ + return false; + } + + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + response.getWriter().println(ApiRes.fail(ApiCodeEnum.SYS_USER_UN_AUDIT).toJSONString()); + response.getWriter().flush(); + return true; + } + + return false; + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/bill/ReconciliationService.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/bill/ReconciliationService.java new file mode 100644 index 0000000..974cfc1 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/bill/ReconciliationService.java @@ -0,0 +1,457 @@ +package com.jeequan.jeepay.bizcommons.manage.bill; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService; +import com.jeequan.jeepay.core.interfaces.bill.IReconciliationService; +import com.jeequan.jeepay.core.interfaces.paychannel.IBillDownloadService; +import com.jeequan.jeepay.core.model.bill.ChannelBill; +import com.jeequan.jeepay.core.model.bill.ChannelBillRQ; +import com.jeequan.jeepay.core.model.bill.ChannelBillRS; +import com.jeequan.jeepay.core.model.bill.LocalBill; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.db.config.dynamic.DataSourceSwitch; +import com.jeequan.jeepay.db.config.dynamic.DynamicDataSource; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.service.impl.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/*** +* 对账接口 +* +* @author zx +* @date 2022/3/12 14:54 +*/ +@Service +@Slf4j +public class ReconciliationService implements IReconciliationService { + + private static final long CHECK_PAGE_SIZE = 1; // 本地订单对账分页数量 + + @Autowired private PayInterfaceConfigService payInterfaceConfigService; + @Autowired private IConfigContextQueryService configContextQueryService; + @Autowired private CheckBatchService checkBatchService; + @Autowired private CheckChannelBillService channelBillService; + @Autowired private CheckChannelBillService checkChannelBillService; + @Autowired private CheckDiffService checkDiffService; + @Autowired private PayOrderService payOrderService; + @Autowired private RefundOrderService refundOrderService; + + /** + * 对账规则:ifCode_channelMchNo_billDate为一个批次,一批一批的对账,即相当于根据 channelMchNo 对账,channelMchNo来自于 PayInterfaceConfig + * 每个PayInterfaceConfig 对应着一个 商户应用/服务商 和一个channelMchNo,但它们是多对一的关系,多个商户应用可能配置相同的channelMchNo + * 根据channelMchNo查询渠道账单,确保了渠道账单只查询一次,不会出现重复 + * 根据商户应用查询本地订单会有漏洞:只查询了某一个商户应用的订单,所以使用去重的channelMchNo对账会出现漏掉本地订单的情况 + * 解决漏洞:匹配到 channelMchNo 对应的所有 商户应用,查询本地订单时使用 + * */ + @Override + public void queryChannelBillAndCheck(String ifCode, Date billDate) { + + IBillDownloadService billDownloadService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "BillDownloadService", IBillDownloadService.class); + if (billDownloadService == null) { + log.info("支付接口:{},暂不支持对账!", ifCode); + return; + } + + // 查询去重的渠道商户号 和 本地支付配置 + List channelBillRQList = buildDistinctIfParams(ifCode); + if(CollUtil.isEmpty(channelBillRQList)){ + log.info("支付接口:{},无支付参数配置!", ifCode); + return; + } + + log.info("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 支付接口ifCode={},开始对账 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓", ifCode); + checkBills4SingleChannel(billDownloadService, ifCode, billDate, channelBillRQList); + log.info("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 支付接口ifCode={},对账结束 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑", ifCode); + } + + @Override + public void reloadBill4Batch(com.jeequan.jeepay.core.entity.CheckBatch checkBatch, String reloadType) { + + String ifCode = checkBatch.getIfCode(); + + IBillDownloadService billDownloadService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(ifCode) + "BillDownloadService", IBillDownloadService.class); + if (billDownloadService == null) { + log.info("支付接口:{},暂不支持对账!", ifCode); + return; + } + + // 解析失败的批次,无渠道账单,本地对应账单会存入差异表,因此需要清掉差异表相关数据 + if (reloadType.equals("release") && checkBatch.getReleaseState() == CS.NO) { + checkDiffService.removeDiffByBatchNo(checkBatch.getBatchNo()); + } + // 解析成功并且处理状态未完成的批次,此时不再下载对账单,应保留渠道账单,需清空差异账单 + else if (reloadType.equals("check") && checkBatch.getReleaseState() == CS.YES && checkBatch.getState() == CS.NO) { + checkDiffService.removeDiffByBatchNo(checkBatch.getBatchNo()); + }else { + return; + } + + List channelBillRQList = buildDistinctIfParams(ifCode); + if (CollUtil.isEmpty(channelBillRQList)) { + return; + } + List collect = channelBillRQList.stream().filter(channelBillRQ -> channelBillRQ.getChannelMchNo().equals(checkBatch.getChannelMchNo())).collect(Collectors.toList()); + if (CollUtil.isEmpty(collect)) { + return; + } + + ChannelBillRQ channelBillRQ = collect.get(0); + + checkBills4Batch(billDownloadService, ifCode, checkBatch.getBillDate(), channelBillRQ); + } + + // 处理差异 + @Override + public void processCheckDiffBills(Date billDate) { + + // 处理开始时间:对账日期前三天 + Date beginDate = DateUtil.offsetDay(billDate, -3); + + List checkDiffList = checkDiffService.list(CheckDiff.gw() + .in(CheckDiff::getHandleState, Arrays.asList(CheckDiff.HANDLE_STATE_WAITING, CheckDiff.HANDLE_STATE_HANG_UP)) + .in(CheckDiff::getDiffType, Arrays.asList(CheckDiff.DIFF_TYPE_LOCAL, CheckDiff.DIFF_TYPE_CHANNEL)) + .ge(CheckDiff::getBillDate, DateUtil.beginOfDay(beginDate)) + .le(CheckDiff::getBillDate, DateUtil.endOfDay(billDate)) + ); + + Map localDiffMap = new HashMap<>(); // 本地多帐数据 + Map channelDiffMap = new HashMap<>(); // 渠道多帐数据 + + checkDiffList.forEach(checkDiff -> { + if (CheckDiff.DIFF_TYPE_LOCAL.equals(checkDiff.getDiffType())) { + localDiffMap.put(checkDiff.getOrderId(), checkDiff); + }else { + channelDiffMap.put(checkDiff.getOrderId(), checkDiff); + } + }); + + // 平账数据 + List checkSuccessList = new ArrayList<>(); + + // 核对本地多帐和渠道多帐数据,将平账数据取出 + localDiffMap.forEach((key, localCheckDiff) -> { + if (channelDiffMap.containsKey(key)) { + + CheckDiff channelCheckDiff = channelDiffMap.get(key); + if (localCheckDiff.getAmount().equals(channelCheckDiff.getChannelAmount()) && localCheckDiff.getFeeAmount().equals(channelCheckDiff.getChannelFeeAmount())) { + checkSuccessList.add(localCheckDiff); + checkSuccessList.add(channelCheckDiff); + } + } + }); + + // 更新平账数据为已处理 + checkDiffService.updateHandleStateSuccess(checkSuccessList); + + // 三天前的差异对账单,状态由挂单改为未处理 + checkDiffService.updateHandleStateHangUp2Waiting(beginDate); + + // 更新三天内的批次统计数据 + checkBatchService.updateUnHandleCountAndState4CheckDiff(checkSuccessList); + } + + /** 渠道对账 */ + public void checkBills4SingleChannel(IBillDownloadService billDownloadService, String ifCode, Date billDate, List channelBillRQList) { + // 查询渠道对账单 && 入库 + for (ChannelBillRQ channelBillRQ : channelBillRQList) { + try { + checkBills4Batch(billDownloadService, ifCode, billDate, channelBillRQ); + }catch (Exception e) { + log.error("对账单处理失败,支付接口:{},渠道商户号:{},对账日期:{}", ifCode, channelBillRQ.getChannelMchNo(), billDate, e); + } + } + } + + /** 构建全部服务商、商户的渠道商户号与服务商或应用的配置关系 */ + public List buildDistinctIfParams(String ifCode) { + List channelBillRQList = payInterfaceConfigService.selectDistinctIsvIfParams(ifCode); // 查询服务商渠道号 与 服务商号及配置参数对应关系 + channelBillRQList.addAll(payInterfaceConfigService.selectDistinctIsvSubMchIfParams(ifCode)); // 查询特约商户 与 商户应用及配置参数对应关系 + channelBillRQList.addAll(payInterfaceConfigService.selectDistinctNormalMchIfParams(ifCode)); // 查询普通商户 与 商户应用及配置参数对应关系 + return channelBillRQList; + } + + public void checkBills4Batch(IBillDownloadService billDownloadService, String ifCode, Date billDate, ChannelBillRQ channelBillRQ) { + + String channelMchNo = channelBillRQ.getChannelMchNo(); // 渠道商户号 + List infoIdList = channelBillRQ.getInfoIdList(); // channelMchNo 对应的 全部商户应用appId或服务商号集合 + + String batchNo = checkBatchService.getBatchNo(ifCode, channelMchNo, billDate); + log.info("批次对账开始,对账批次号:{}", batchNo); + + // 查询当前批次信息 + CheckBatch dbCheckBatch = checkBatchService.getById(batchNo); + + // 当前批次已解析成功,直接进行对账 + if (dbCheckBatch != null && dbCheckBatch.getReleaseState() == CS.YES) { + checkBills4Batch(dbCheckBatch, infoIdList, channelBillRQ.getInfoType()); + return; + } + + + // 解析对账单 && 对账 + MchAppConfigContext mchAppConfigContext = null; + if (ChannelBillRQ.INFO_TYPE_SUB.equals(channelBillRQ.getInfoType()) || ChannelBillRQ.INFO_TYPE_NORMAL.equals(channelBillRQ.getInfoType())) { + mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(channelBillRQ.getInfoId()); + if (mchAppConfigContext == null) { + throw new BizException("获取商户应用信息失败"); + } + } + + // 下载并转为系统的标准对账单 + ChannelBillRS channelBillRes = billDownloadService.convertStandardBill(channelBillRQ, mchAppConfigContext, billDate, ifCode); + if (channelBillRes == null || channelBillRes.getCheckBatch() == null) { + throw new BizException("对账失败,对账批次为空!"); + } + + // 保存对账批次,对账批次下载/解析失败的,直接结束 + CheckBatch checkBatch = checkBatchService.saveOrUpdateCheckBatch(channelBillRes.getCheckBatch()); + if (checkBatch.getReleaseState() == CS.NO) { + throw new BizException(checkBatch.getReleaseErrMsg()); + } + + // 服务商维度、服务商子商户维度,不对账的渠道子商户号集合 + if (StringUtils.equalsAny(channelBillRQ.getInfoType(), ChannelBillRQ.INFO_TYPE_ISV, ChannelBillRQ.INFO_TYPE_SUB)) { + Set ignoreCheckBillMchNos = channelBillRQ.getIgnoreCheckBillMchNos(); + if (CollUtil.isNotEmpty(ignoreCheckBillMchNos) && CollUtil.isNotEmpty(channelBillRes.getChannelBillList())) { + List filterList = channelBillRes.getChannelBillList().stream().filter(channelBill -> !ignoreCheckBillMchNos.contains(channelBill.getChannelMchNo())).collect(Collectors.toList()); + channelBillRes.setChannelBillList(filterList); + } + } + + // 保存渠道对账单 + channelBillService.saveChannelBills(channelBillRes.getChannelBillList()); + + // 当前批次对账 + checkBills4Batch(checkBatch, infoIdList, channelBillRQ.getInfoType()); + } + + /** 单个批次对账 */ + public void checkBills4Batch(CheckBatch checkBatch, List infoIdList, String infoType) { + + // 查询当前批次渠道对账单 + List channelList = channelBillService.selectListByCheckBatchNo(checkBatch.getBatchNo()); + + long pageNo = 1; // 页码: 默认第一页 + long[] totalPayOrderPage = { 1 }; // 支付订单总页码 + List totalLocalDiffBills = new ArrayList<>(); // 所有本地多帐差异 + List totalChannelDiffBills = new ArrayList<>(); // 所有渠道多帐差异 + List totalOrderDiffBills = new ArrayList<>(); // 所有金额差异 + + // 本地账单数据统计 + CheckBatch updateDataRecord = checkBatchService.initLocalCheckBatchData(checkBatch); + + while (true) { + // 2、处理当前支付接口本地订单数据 + List localBillList = getLocalOrderBills(pageNo++, totalPayOrderPage, updateDataRecord, infoIdList, infoType); + + // 本地账单为空,渠道也为空,对账结束 + if (CollUtil.isEmpty(localBillList) && CollUtil.isEmpty(channelList)) { + break; + } + + // 本地账单为空,渠道不为空,渠道账单记录为差异订单,类型为渠道多帐 + if (CollUtil.isEmpty(localBillList) && CollUtil.isNotEmpty(channelList)) { + totalChannelDiffBills.addAll(checkDiffService.covertChannelBillToCheckDiff(channelList)); + break; + } + + // 本地账单不为空,渠道为空,本地账单记录为差异订单,类型为本地多帐,继续循环 + if (CollUtil.isNotEmpty(localBillList) && CollUtil.isEmpty(channelList)) { + totalLocalDiffBills.addAll(localBillList); + continue; + } + + // ↓↓↓↓↓↓↓↓↓↓ 本地账单不为空,渠道不为空 ↓↓↓↓↓↓↓↓↓↓↓ + // 3、核对渠道、本地数据,得到差异订单 + checkBills(channelList, localBillList, totalLocalDiffBills, totalOrderDiffBills); + } + + // 差异订单 存入差异表 + checkDiffService.saveBatchDiffBills(totalLocalDiffBills, totalChannelDiffBills, totalOrderDiffBills, updateDataRecord); + log.info("批次对账结束,对账批次号:{},本地多账总数={},渠道多账总数={},订单差异总数={}", + checkBatch.getBatchNo(), totalLocalDiffBills.size(), totalChannelDiffBills.size(), totalOrderDiffBills.size()); + } + + + // 对账,差异存入差异表 + private void checkBills(List channelBillList, List localBillList, + List totalLocalDiffBills, List totalOrderDiffBills) { + + // 本地账单数据转Map,key -> 商户单号,value:账单对象 + Map localBillMap = localBillList.stream().collect(Collectors.toMap(LocalBill::getOrderId, o -> o)); + + // 遍历渠道账单 + Iterator it = channelBillList.iterator(); + while (it.hasNext()) { + CheckChannelBill channelBill = it.next(); // 渠道对账单 + + // 支付订单有平台订单号,退款也有平台退款商户号的情况,其他情况见了再优化 + if (StringUtils.isNotBlank(channelBill.getOrderId())) { + if (localBillMap.containsKey(channelBill.getOrderId())) { + LocalBill localBill = localBillMap.get(channelBill.getOrderId()); // 本地对账单 + + // 校验订单金额(订单号一致,金额不等,本地、渠道两笔账单记录为订单差异并保存至差异表) + // 校验手续费,只有支付订单校验手续费 + if (!localBill.getAmount().equals(channelBill.getChannelAmount()) || + (CheckChannelBill.BILL_TYPE_PAY.equals(localBill.getBillType()) && !localBill.getFeeAmount().equals(channelBill.getChannelFeeAmount()))) { + // 金额不一致,记录为订单差异类型,本地、渠道数据需删除当前账单 + totalOrderDiffBills.add(checkDiffService.covertToOrderCheckDiff(channelBill, localBill, CheckDiff.DIFF_TYPE_ORDER)); + } + + // 金额一致,本地、渠道数据删除当前账单 + localBillMap.remove(localBill.getOrderId()); + it.remove(); + } + } + } + + // 当前循环本地多帐订单存入总差异列表 + if (CollUtil.isNotEmpty(localBillMap)) { + totalLocalDiffBills.addAll(new ArrayList<>(localBillMap.values())); + } + } + + // 生成本地对账数据 + @DataSourceSwitch(DynamicDataSource.DataSourceTypeEnum.SLAVE) + private List getLocalOrderBills(long pageNo, long[] totalPayOrderPage, CheckBatch updateDataRecord, List infoIdList, String infoType) { + + String ifCode = updateDataRecord.getIfCode(); + Date billDate = updateDataRecord.getBillDate(); + + if (pageNo <= totalPayOrderPage[0]) { + // 查询支付成功的,部分退款和全额退款均认为交易成功记录 + IPage payOrderPage = payOrderService.page(getIPage(pageNo), PayOrder.gw() + .select(PayOrder::getPayOrderId, PayOrder::getMchNo, PayOrder::getMchName, PayOrder::getAppId, PayOrder::getMchOrderNo, PayOrder::getAmount, + PayOrder::getMchOrderFeeAmount, PayOrder::getRefundAmount, PayOrder::getState, PayOrder::getSuccessTime, PayOrder::getCreatedAt) + .and(i -> i.eq(PayOrder::getState, PayOrder.STATE_SUCCESS).or().in(PayOrder::getRefundState, Arrays.asList(PayOrder.REFUND_STATE_SUB, PayOrder.REFUND_STATE_ALL))) + .in(ChannelBillRQ.INFO_TYPE_ISV.equals(infoType), PayOrder::getIsvNo, infoIdList) + .in(!ChannelBillRQ.INFO_TYPE_ISV.equals(infoType), PayOrder::getAppId, infoIdList) + .eq(PayOrder::getIfCode, ifCode) + .ge(PayOrder::getCreatedAt, billDate) + .le(PayOrder::getCreatedAt, DateUtil.endOfDay(billDate)) + ); + + totalPayOrderPage[0] = payOrderPage.getTotal(); + + // 当前页码 <= 订单表总页码 + if (CollUtil.isNotEmpty(payOrderPage.getRecords())) { + return covertPayOrderToLocalBill(payOrderPage.getRecords(), updateDataRecord); + } + } + + + // 当前页码 > 订单总页码,开始查询退款订单表,退款页码=当前页码 - 支付订单总页码 + long refundPageNo = pageNo - totalPayOrderPage[0]; + + IPage refundOrderPage = refundOrderService.page(getIPage(refundPageNo), RefundOrder.gw() + .select(RefundOrder::getRefundOrderId, RefundOrder::getMchNo, RefundOrder::getMchName, RefundOrder::getAppId, RefundOrder::getMchRefundNo, + RefundOrder::getPayAmount, RefundOrder::getRefundAmount, RefundOrder::getState, RefundOrder::getSuccessTime, RefundOrder::getCreatedAt) + .eq(RefundOrder::getState, RefundOrder.STATE_SUCCESS) + .in(ChannelBillRQ.INFO_TYPE_ISV.equals(infoType), RefundOrder::getIsvNo, infoIdList) + .in(!ChannelBillRQ.INFO_TYPE_ISV.equals(infoType), RefundOrder::getAppId, infoIdList) + .eq(RefundOrder::getIfCode, ifCode) + .ge(RefundOrder::getCreatedAt, billDate) + .le(RefundOrder::getCreatedAt, DateUtil.endOfDay(billDate)) + ); + + return covertRefundOrderToLocalBill(refundOrderPage.getRecords(), updateDataRecord); + } + + + // 支付订单 转换为 本地标准账单 + private List covertPayOrderToLocalBill(List payOrderList, CheckBatch updateDataRecord) { + if (CollUtil.isEmpty(payOrderList)) { + return null; + } + + // 统计数组,数据分别为:订单总数 总金额 总手续费 + final long[] totalOrderData = { 0, 0, 0 }; + + List localBillList = payOrderList.stream().map(payOrder -> { + LocalBill localOrderBill = new LocalBill(); + localOrderBill.setIfCode(updateDataRecord.getIfCode()); + localOrderBill.setBillDate(updateDataRecord.getBillDate()); + localOrderBill.setChannelMchNo(updateDataRecord.getChannelMchNo()); + localOrderBill.setOrderId(payOrder.getPayOrderId()); + localOrderBill.setBillType(CheckChannelBill.BILL_TYPE_PAY); + localOrderBill.setMchNo(payOrder.getMchNo()); + localOrderBill.setMchName(payOrder.getMchName()); + localOrderBill.setMchAppId(payOrder.getAppId()); + localOrderBill.setMchOrderNo(payOrder.getMchOrderNo()); + localOrderBill.setAmount(payOrder.getAmount()); + localOrderBill.setFeeAmount(payOrder.getMchOrderFeeAmount()); + localOrderBill.setOrderState(payOrder.getState()); + localOrderBill.setOrderSuccessAt(payOrder.getSuccessTime()); + localOrderBill.setOrderCreateAt(payOrder.getCreatedAt()); + + totalOrderData[0]++; + totalOrderData[1] += payOrder.getAmount(); + totalOrderData[2] += payOrder.getMchOrderFeeAmount(); + + return localOrderBill; + }).collect(Collectors.toList()); + + updateDataRecord.setTotalCount(updateDataRecord.getTotalCount() + Math.toIntExact(totalOrderData[0])); + updateDataRecord.setTotalAmount(updateDataRecord.getTotalAmount() + totalOrderData[1]); + updateDataRecord.setTotalFee(updateDataRecord.getTotalFee() + totalOrderData[2]); + + return localBillList; + } + + // 退款订单 转换为 本地标准账单 + private List covertRefundOrderToLocalBill(List refundOrderList, CheckBatch updateDataRecord) { + if (CollUtil.isEmpty(refundOrderList)) { + return null; + } + + // 统计数组,数据分别为:订单总数 总金额 总手续费 + final long[] totalRefundOrderData = { 0, 0, 0 }; + + List localBillList = refundOrderList.stream().map(refundOrder -> { + LocalBill localOrderBill = new LocalBill(); + localOrderBill.setIfCode(updateDataRecord.getIfCode()); + localOrderBill.setBillDate(updateDataRecord.getBillDate()); + localOrderBill.setChannelMchNo(updateDataRecord.getChannelMchNo()); + localOrderBill.setOrderId(refundOrder.getRefundOrderId()); + localOrderBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND); + localOrderBill.setMchNo(refundOrder.getMchNo()); + localOrderBill.setMchName(refundOrder.getMchName()); + localOrderBill.setMchAppId(refundOrder.getAppId()); + localOrderBill.setMchOrderNo(refundOrder.getMchRefundNo()); + localOrderBill.setAmount(refundOrder.getRefundAmount()); + localOrderBill.setRefundState(refundOrder.getState()); + localOrderBill.setOrderSuccessAt(refundOrder.getSuccessTime()); + localOrderBill.setOrderCreateAt(refundOrder.getCreatedAt()); + + totalRefundOrderData[0]++; + totalRefundOrderData[1] += refundOrder.getRefundAmount(); + totalRefundOrderData[2] += refundOrder.getRefundFeeAmount(); + + return localOrderBill; + }).collect(Collectors.toList()); + + updateDataRecord.setTotalRefundCount(updateDataRecord.getTotalRefundCount() + Math.toIntExact(totalRefundOrderData[0])); + updateDataRecord.setTotalRefundAmount(updateDataRecord.getTotalRefundAmount() + totalRefundOrderData[1]); + updateDataRecord.setTotalFee(updateDataRecord.getTotalFee() - totalRefundOrderData[2]); + + return localBillList; + } + + protected IPage getIPage(long pageIndex){ + return new Page(pageIndex, CHECK_PAGE_SIZE); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/email/EmailManager.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/email/EmailManager.java new file mode 100644 index 0000000..bd65c7c --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/email/EmailManager.java @@ -0,0 +1,117 @@ +package com.jeequan.jeepay.bizcommons.manage.email; + +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.DBEmailConfig; +import com.jeequan.jeepay.service.impl.SysConfigService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +import javax.mail.Authenticator; +import javax.mail.MessagingException; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * 发送电子邮件相关的功能service + * @author nb2020 + */ +@Slf4j +@Component +public class EmailManager { + + @Autowired + private SysConfigService sysConfigService; + + public JavaMailSender mailSender; + + public DBEmailConfig getInstance(){ + DBEmailConfig emailConfig = sysConfigService.getEmailConfig(); + if(emailConfig == null){ + throw new BizException("未开启邮箱配置"); + } + JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); + javaMailSender.setHost(emailConfig.getEmailHost()); + javaMailSender.setDefaultEncoding("utf-8"); + javaMailSender.setPort(emailConfig.getEmailPort()); + javaMailSender.setUsername(emailConfig.getEmailAccountNo()); + javaMailSender.setPassword(emailConfig.getEmailPassword()); + Properties props = System.getProperties(); + props.put("mail.smtp.host", emailConfig.getEmailHost()); + props.put("mail.username", emailConfig.getEmailAccountNo()); + props.put("mail.password", emailConfig.getEmailPassword()); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.fallback", "false"); + props.put("mail.smtp.port", emailConfig.getEmailPort()); + props.put("mail.smtp.socketFactory.port", emailConfig.getEmailPort()); + props.put("mail.smtp.auth", "true"); + Session session = Session.getDefaultInstance(props, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(props.getProperty("mail.username"), props.getProperty("mail.password")); + } + }); + javaMailSender.setSession(session); + mailSender = javaMailSender; + return emailConfig; + } + + + public EmailManager() { + System.setProperty("mail.mime.splitlongparameters", "false"); + } + + /** + * 发送邮件 + * @param tos 接收人邮箱数组 + * @param ccs 抄送人邮箱数组 + * @param title 邮件主题 + * @param content 邮件内容 + * @param workBook 附件excel + */ + public void sendEmail(String[] tos, String[] ccs, String title, String content, XSSFWorkbook workBook, String workBookName) { + + DBEmailConfig config = getInstance(); + + MimeMessage mimeMessage = mailSender.createMimeMessage(); + + MimeMessageHelper mimeMessageHelper; + + try { + mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "utf-8"); + mimeMessageHelper.setTo(tos); + if (ccs != null) { + mimeMessageHelper.setCc(ccs); + } + mimeMessageHelper.setFrom(config.getEmailName() + "<" + config.getEmailAccountNo() + ">"); + mimeMessageHelper.setSubject(title); + mimeMessageHelper.setText(content); + if(workBook != null){ + ByteArrayOutputStream out = new ByteArrayOutputStream(); + workBook.write(out); + byte[] bookByteArr = out.toByteArray(); + InputStream in = new ByteArrayInputStream(bookByteArr); + String newFileName = MimeUtility.encodeWord(workBookName, "utf-8", "B"); + mimeMessageHelper.addAttachment(newFileName, new ByteArrayResource(IOUtils.toByteArray(in), "application/vnd.ms-excel;charset=UTF-8")); + } + } catch (IOException | MessagingException e) { + log.error("邮件发送失败"); + e.printStackTrace(); + return; + } + mailSender.send(mimeMessage); + } +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/AbstractGenerator.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/AbstractGenerator.java new file mode 100644 index 0000000..47e509b --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/AbstractGenerator.java @@ -0,0 +1,90 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import cn.hutool.core.codec.Base64; +import cn.hutool.http.HttpUtil; +import com.google.zxing.WriterException; +import com.jeequan.jeepay.components.oss.config.OssYmlConfig; +import com.jeequan.jeepay.components.oss.model.OssFileConfig; +import com.jeequan.jeepay.core.utils.FileKit; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +/*** + * 抽象类: 模板生成器 + * + * @author terrfly + * @date 2022/1/18 12:33 + */ +public abstract class AbstractGenerator { + + public static final String DEFAULT_FONT = "微软雅黑"; // 微软雅黑 宋体 + + @Autowired + private OssYmlConfig ossYmlConfig; + + /** + * 功能描述:生成图片的 BufferedImage + * + * @param configModelStr 自行转换 + * @param qrUrlContent 二维码内容 + * @param qrcId 码牌ID + * @param isViewFlag 是否预览模式(将等比例缩小图片) + * @Return: java.awt.image.BufferedImage + * @Author: terrfly + * @Date: 2022/1/18 15:52 + */ + + public abstract BufferedImage genQrImgBuffer(String configModelStr, String qrUrlContent, Long qrcId, String mchStoreName, boolean isViewFlag) throws IOException, WriterException; + + + protected BufferedImage getStaticImg(String img) throws IOException { + return ImageIO.read(new ClassPathResource("static/images/qrshell" + img).getInputStream()); // + } + + /** + * 下载文件进行缓存 & 获取图片 + **/ + protected File downloadAndGetCacheFile(String url) { + + // 下载地址为空 + if (StringUtils.isEmpty(url)) { + return null; + } + + String filePath = ossYmlConfig.getOss().getFilePublicPath() + File.separator + OssFileConfig.BIZ_TYPE.QRC + File.separator + FileKit.getUrlFileName(url); + + // 存在 + if (new File(filePath).exists()) { + return new File(filePath); + } + + // 下载 + HttpUtil.downloadFile(url, filePath); + return new File(filePath); + } + + + public static String convertImgBase64(BufferedImage bufferedImage) throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流 + ImageIO.write(bufferedImage, "jpg", baos);//写入流中 + byte[] bytes = baos.toByteArray();//转换成字节 + String imgBase64 = Base64.encode(bytes); + return imgBase64.replace("\n", "").replace("\r", "");//删除 \r\n + } + + public static ByteArrayInputStream convertInputStream(BufferedImage bufferedImage) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(bufferedImage, "png", os); + return new ByteArrayInputStream(os.toByteArray()); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/CommonConfigModel.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/CommonConfigModel.java new file mode 100644 index 0000000..87fa7b4 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/CommonConfigModel.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import lombok.Data; + +import java.util.List; + +/** +* 通用配置项 +* +* @author terrfly +* @date 2022/3/3 9:54 +*/ +@Data +public class CommonConfigModel { + + /** 是否显示ID号, 初始化model为false **/ + protected boolean showIdFlag; + + /** 是否显示门店名称 **/ + protected boolean showStoreNameFlag; + + /** 支付方式列表 **/ + protected List payTypeList; + + /** 背景颜色 */ + protected String bgColor; + + /** 描述文本 */ + protected String descText; + + /** 二维码中间图片 */ + protected String qrInnerImgUrl; + + /** logo图片 */ + protected String logoImgUrl; + + /** 二维码图片的支付方式 **/ + @Data + public static class PayType{ + + /** 支付方式 name **/ + private String name; + + /** 支付方式名称 自定义 **/ + private String alias; + + /** 图片地址, 若内置类型 为: alipay, wxpay, unionpay , ysfpay 其他为url地址 **/ + private String imgUrl; + + } +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/HSLColor.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/HSLColor.java new file mode 100644 index 0000000..e0858c3 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/HSLColor.java @@ -0,0 +1,434 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import java.awt.*; + +/** + * + * 来源: + * https://www.coder.work/article/388801 + * http://www.camick.com/java/source/HSLColor.java + * 新增: 颜色加深代码 + * + * The HSLColor class provides methods to manipulate HSL (Hue, Saturation + * Luminance) values to create a corresponding Color object using the RGB + * ColorSpace. + * + * The HUE is the color, the Saturation is the purity of the color (with + * respect to grey) and Luminance is the brightness of the color (with respect + * to black and white) + * + * The Hue is specified as an angel between 0 - 360 degrees where red is 0, + * green is 120 and blue is 240. In between you have the colors of the rainbow. + * Saturation is specified as a percentage between 0 - 100 where 100 is fully + * saturated and 0 approaches gray. Luminance is specified as a percentage + * between 0 - 100 where 0 is black and 100 is white. + * + * In particular the HSL color space makes it easier change the Tone or Shade + * of a color by adjusting the luminance value. + */ +public class HSLColor +{ + private Color rgb; + private float[] hsl; + private float alpha; + + /** + * Create a HSLColor object using an RGB Color object. + * + * @param rgb the RGB Color object + */ + public HSLColor(Color rgb) + { + this.rgb = rgb; + hsl = fromRGB( rgb ); + alpha = rgb.getAlpha() / 255.0f; + } + + /** + * Create a HSLColor object using individual HSL values and a default + * alpha value of 1.0. + * + * @param h is the Hue value in degrees between 0 - 360 + * @param s is the Saturation percentage between 0 - 100 + * @param l is the Lumanance percentage between 0 - 100 + */ + public HSLColor(float h, float s, float l) + { + this(h, s, l, 1.0f); + } + + /** + * Create a HSLColor object using individual HSL values. + * + * @param h the Hue value in degrees between 0 - 360 + * @param s the Saturation percentage between 0 - 100 + * @param l the Lumanance percentage between 0 - 100 + * @param alpha the alpha value between 0 - 1 + */ + public HSLColor(float h, float s, float l, float alpha) + { + hsl = new float[] {h, s, l}; + this.alpha = alpha; + rgb = toRGB(hsl, alpha); + } + + /** + * Create a HSLColor object using an an array containing the + * individual HSL values and with a default alpha value of 1. + * + * @param hsl array containing HSL values + */ + public HSLColor(float[] hsl) + { + this(hsl, 1.0f); + } + + /** + * Create a HSLColor object using an an array containing the + * individual HSL values. + * + * @param hsl array containing HSL values + * @param alpha the alpha value between 0 - 1 + */ + public HSLColor(float[] hsl, float alpha) + { + this.hsl = hsl; + this.alpha = alpha; + rgb = toRGB(hsl, alpha); + } + + /** + * Create a RGB Color object based on this HSLColor with a different + * Hue value. The degrees specified is an absolute value. + * + * @param degrees - the Hue value between 0 - 360 + * @return the RGB Color object + */ + public Color adjustHue(float degrees) + { + return toRGB(degrees, hsl[1], hsl[2], alpha); + } + + /** + * Create a RGB Color object based on this HSLColor with a different + * Luminance value. The percent specified is an absolute value. + * + * @param percent - the Luminance value between 0 - 100 + * @return the RGB Color object + */ + public Color adjustLuminance(float percent) + { + return toRGB(hsl[0], hsl[1], percent, alpha); + } + + /** + * Create a RGB Color object based on this HSLColor with a different + * Saturation value. The percent specified is an absolute value. + * + * @param percent - the Saturation value between 0 - 100 + * @return the RGB Color object + */ + public Color adjustSaturation(float percent) + { + return toRGB(hsl[0], percent, hsl[2], alpha); + } + + /** + * Create a RGB Color object based on this HSLColor with a different + * Shade. Changing the shade will return a darker color. The percent + * specified is a relative value. + * + * @param percent - the value between 0 - 100 + * @return the RGB Color object + */ + public Color adjustShade(float percent) + { + float multiplier = (100.0f - percent) / 100.0f; + float l = Math.max(0.0f, hsl[2] * multiplier); + + return toRGB(hsl[0], hsl[1], l, alpha); + } + + /** + * Create a RGB Color object based on this HSLColor with a different + * Tone. Changing the tone will return a lighter color. The percent + * specified is a relative value. + * + * @param percent - the value between 0 - 100 + * @return the RGB Color object + */ + public Color adjustTone(float percent) + { + float multiplier = (100.0f + percent) / 100.0f; + float l = Math.min(100.0f, hsl[2] * multiplier); + + return toRGB(hsl[0], hsl[1], l, alpha); + } + + /** + * Get the Alpha value. + * + * @return the Alpha value. + */ + public float getAlpha() + { + return alpha; + } + + /** + * Create a RGB Color object that is the complementary color of this + * HSLColor. This is a convenience method. The complementary color is + * determined by adding 180 degrees to the Hue value. + * @return the RGB Color object + */ + public Color getComplementary() + { + float hue = (hsl[0] + 180.0f) % 360.0f; + return toRGB(hue, hsl[1], hsl[2]); + } + + /** + * Get the Hue value. + * + * @return the Hue value. + */ + public float getHue() + { + return hsl[0]; + } + + /** + * Get the HSL values. + * + * @return the HSL values. + */ + public float[] getHSL() + { + return hsl; + } + + /** + * Get the Luminance value. + * + * @return the Luminance value. + */ + public float getLuminance() + { + return hsl[2]; + } + + /** + * Get the RGB Color object represented by this HDLColor. + * + * @return the RGB Color object. + */ + public Color getRGB() + { + return rgb; + } + + /** + * Get the Saturation value. + * + * @return the Saturation value. + */ + public float getSaturation() + { + return hsl[1]; + } + + public String toString() + { + String toString = + "HSLColor[h=" + hsl[0] + + ",s=" + hsl[1] + + ",l=" + hsl[2] + + ",alpha=" + alpha + "]"; + + return toString; + } + + /** + * Convert a RGB Color to it corresponding HSL values. + * + * @return an array containing the 3 HSL values. + */ + public static float[] fromRGB(Color color) + { + // Get RGB values in the range 0 - 1 + + float[] rgb = color.getRGBColorComponents( null ); + float r = rgb[0]; + float g = rgb[1]; + float b = rgb[2]; + + // Minimum and Maximum RGB values are used in the HSL calculations + + float min = Math.min(r, Math.min(g, b)); + float max = Math.max(r, Math.max(g, b)); + + // Calculate the Hue + + float h = 0; + + if (max == min) + h = 0; + else if (max == r) + h = ((60 * (g - b) / (max - min)) + 360) % 360; + else if (max == g) + h = (60 * (b - r) / (max - min)) + 120; + else if (max == b) + h = (60 * (r - g) / (max - min)) + 240; + + // Calculate the Luminance + + float l = (max + min) / 2; + + // Calculate the Saturation + + float s = 0; + + if (max == min) + s = 0; + else if (l <= .5f) + s = (max - min) / (max + min); + else + s = (max - min) / (2 - max - min); + + return new float[] {h, s * 100, l * 100}; + } + + /** + * Convert HSL values to a RGB Color with a default alpha value of 1. + * H (Hue) is specified as degrees in the range 0 - 360. + * S (Saturation) is specified as a percentage in the range 1 - 100. + * L (Lumanance) is specified as a percentage in the range 1 - 100. + * + * @param hsl an array containing the 3 HSL values + * + * @returns the RGB Color object + */ + public static Color toRGB(float[] hsl) + { + return toRGB(hsl, 1.0f); + } + + /** + * Convert HSL values to a RGB Color. + * H (Hue) is specified as degrees in the range 0 - 360. + * S (Saturation) is specified as a percentage in the range 1 - 100. + * L (Lumanance) is specified as a percentage in the range 1 - 100. + * + * @param hsl an array containing the 3 HSL values + * @param alpha the alpha value between 0 - 1 + * + * @returns the RGB Color object + */ + public static Color toRGB(float[] hsl, float alpha) + { + return toRGB(hsl[0], hsl[1], hsl[2], alpha); + } + + /** + * Convert HSL values to a RGB Color with a default alpha value of 1. + * + * @param h Hue is specified as degrees in the range 0 - 360. + * @param s Saturation is specified as a percentage in the range 1 - 100. + * @param l Lumanance is specified as a percentage in the range 1 - 100. + * + * @returns the RGB Color object + */ + public static Color toRGB(float h, float s, float l) + { + return toRGB(h, s, l, 1.0f); + } + + /** + * Convert HSL values to a RGB Color. + * + * @param h Hue is specified as degrees in the range 0 - 360. + * @param s Saturation is specified as a percentage in the range 1 - 100. + * @param l Lumanance is specified as a percentage in the range 1 - 100. + * @param alpha the alpha value between 0 - 1 + * + * @returns the RGB Color object + */ + public static Color toRGB(float h, float s, float l, float alpha) + { + if (s <0.0f || s > 100.0f) + { + String message = "Color parameter outside of expected range - Saturation"; + throw new IllegalArgumentException( message ); + } + + if (l <0.0f || l > 100.0f) + { + String message = "Color parameter outside of expected range - Luminance"; + throw new IllegalArgumentException( message ); + } + + if (alpha <0.0f || alpha > 1.0f) + { + String message = "Color parameter outside of expected range - Alpha"; + throw new IllegalArgumentException( message ); + } + + // Formula needs all values between 0 - 1. + + h = h % 360.0f; + h /= 360f; + s /= 100f; + l /= 100f; + + float q = 0; + + if (l < 0.5) + q = l * (1 + s); + else + q = (l + s) - (s * l); + + float p = 2 * l - q; + + float r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f))); + float g = Math.max(0, HueToRGB(p, q, h)); + float b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f))); + + r = Math.min(r, 1.0f); + g = Math.min(g, 1.0f); + b = Math.min(b, 1.0f); + + return new Color(r, g, b, alpha); + } + + private static float HueToRGB(float p, float q, float h) + { + if (h < 0) h += 1; + + if (h > 1 ) h -= 1; + + if (6 * h < 1) + { + return p + ((q - p) * 6 * h); + } + + if (2 * h < 1 ) + { + return q; + } + + if (3 * h < 2) + { + return p + ( (q - p) * 6 * ((2.0f / 3.0f) - h) ); + } + + return p; + } + + + /** 颜色加深, 比例: 如加深 20%传入 20 ( 若为负数则取绝对值 ) **/ + public static final Color deepen(Color color, int scale){ + HSLColor hslColor = new HSLColor(color); + return HSLColor.toRGB(hslColor.getHue(), hslColor.getSaturation(), Math.abs(hslColor.getLuminance() - scale) ); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellAGenerator.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellAGenerator.java new file mode 100644 index 0000000..8e3fe44 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellAGenerator.java @@ -0,0 +1,260 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import com.alibaba.fastjson.JSON; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.*; + +/** +* shellA 图片生成器 +* +* @author terrfly +* @date 2022/1/17 17:36 +*/ +@Data +@Service +public class ShellAGenerator extends AbstractGenerator { + + /** 生成二维码图片的 buffer缓冲值 **/ + @Override + public BufferedImage genQrImgBuffer(String configModelStr, String qrUrlContent, Long qrcId, String mchStoreName, boolean isViewFlag) throws IOException, WriterException { + + CommonConfigModel configModel = JSON.parseObject(configModelStr, CommonConfigModel.class); + + String qrId = "No." + qrcId.toString(); + + //图片的宽和高 + int imgWidth = 308 * 3; //924 + int imgHeight = 450 * 3; //1350 + + BufferedImage bufferedImage = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB); + + //设置: 全局背景颜色为白色 + Graphics2D graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.white);//背景设置为白色 + graphic.fillRect(0, 0, imgWidth, imgHeight); + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + + //设置: 二维码背景颜色 + graphic = bufferedImage.createGraphics(); + graphic.setColor( new Color(Integer.parseInt(StringUtils.defaultIfEmpty(configModel.getBgColor(), "#5094d5").substring(1),16)) );//背景色的设置 + graphic.fillRect(0, 330, imgWidth, 825); + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + + //设置:二维码上的文字 + if(StringUtils.isNotEmpty(configModel.getDescText())){ + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font font = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 48); + FontMetrics metrics = graphic.getFontMetrics(font); + int x = (imgWidth - metrics.stringWidth(configModel.getDescText())) / 2; + + graphic.setFont(font); //字体、字型、字号 + graphic.drawString(configModel.getDescText(), x, 300); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + + if(configModel.isShowIdFlag()){ + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.white);//背景设置为白色 + + Font qrIdFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 27); + FontMetrics metrics = graphic.getFontMetrics(qrIdFont); + int x = (imgWidth - metrics.stringWidth(qrId)) / 2; + + graphic.setFont(qrIdFont); //字体、字型、字号 + graphic.drawString(qrId , x, 1100); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + //设置:二维码背景图 + BufferedImage waterImg = getStaticImg("/shellA/i_bg.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg, 120, 400, waterImg.getWidth(), waterImg.getHeight(), null); + graphic.dispose(); + + //顶部 logo + List topImgArray = new ArrayList<>(); + if(configModel.getPayTypeList() != null){ + for (CommonConfigModel.PayType payType : configModel.payTypeList) { + if("unionpay".equals(payType.getName()) || "ysfpay".equals(payType.getName()) ||"wxpay".equals(payType.getName()) || "alipay".equals(payType.getName()) ){ + topImgArray.add(getStaticImg("/commons/" + "t_" + payType.getName() + ".png")); + }else{ + File imgFile = downloadAndGetCacheFile(payType.getImgUrl()); // 下载图片 + if(imgFile != null){ + topImgArray.add(ImageIO.read(imgFile)); + } + } + } + } + + List areaArrays = getPayTypeLocation(topImgArray.size()); + if(areaArrays != null && !areaArrays.isEmpty()){ + for (int i = 0; i < areaArrays.size() ;i++) { + BufferedImage waterImg1 = topImgArray.get(i); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg1, areaArrays.get(i)[0], areaArrays.get(i)[1], waterImg1.getWidth(), waterImg1.getHeight(), null); + graphic.dispose(); + + } + } + + //设置:二维码 190X190 + //生成真实的二维码图片 + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + BitMatrix bitMatrix = new MultiFormatWriter().encode(qrUrlContent, BarcodeFormat.QR_CODE, 570, 570, hints);// 生成矩阵 + BufferedImage waterQrImg = MatrixToImageWriter.toBufferedImage(bitMatrix); + + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterQrImg, 178, 466, waterQrImg.getWidth(), waterQrImg.getHeight(), null); + graphic.dispose(); + + + //二维码中间logo + if(StringUtils.isNotEmpty(configModel.getQrInnerImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getQrInnerImgUrl()); + if(imgFile != null){ + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterLogo, 420, 666, 80, 80, null); + graphic.dispose(); + } + } + + //底部logo + if(StringUtils.isNotEmpty(configModel.getLogoImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getLogoImgUrl()); + if(imgFile != null){ + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + + int bottomHeight = imgHeight - 330 - 825; //底部背景高度 + int graphicHeight = 330 + 825 + ((bottomHeight - waterLogo.getHeight()) / 2); //画图的高度 + + graphic.drawImage(waterLogo, ((imgWidth-waterLogo.getWidth()) / 2) , graphicHeight, waterLogo.getWidth(), waterLogo.getHeight(), null); + graphic.dispose(); + } + } + + // 预览需要缩小三倍 + return isViewFlag ? zoomOutImage(bufferedImage, 2) : bufferedImage; + } + + + public static BufferedImage zoomOutImage(BufferedImage originalImage, Integer times){ + + int width = originalImage.getWidth()/times; + if(width < 0){ + width=originalImage.getWidth(); + } + int height = originalImage.getHeight()/times; + if(height < 0){ + height=originalImage.getHeight(); + } + BufferedImage newImage = new BufferedImage(width,height,originalImage.getType()); + + Graphics g = newImage.getGraphics(); + + g.drawImage(originalImage, 0,0,width,height,null); + + g.dispose(); + + return newImage; + + } + + + /** + * + * @Title: 构造图片 + * @Description: 生成水印并返回java.awt.image.BufferedImage + * @param file + * 源文件(图片) + * @param waterFile + * 水印文件(图片) + * @param x + * 距离右下角的X偏移量 + * @param y + * 距离右下角的Y偏移量 + * @param alpha + * 透明度, 选择值从0.0~1.0: 完全透明~完全不透明 + * @return BufferedImage + * @throws IOException + */ + public static BufferedImage watermark(File file, File waterFile, int x, int y, float alpha) throws IOException { + // 获取底图 + BufferedImage buffImg = ImageIO.read(file); + // 获取层图 + BufferedImage waterImg = ImageIO.read(waterFile); + // 创建Graphics2D对象,用在底图对象上绘图 + Graphics2D g2d = buffImg.createGraphics(); + int waterImgWidth = waterImg.getWidth();// 获取层图的宽度 + int waterImgHeight = waterImg.getHeight();// 获取层图的高度 + // 在图形和图像中实现混合和透明效果 + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + // 绘制 + g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null); + g2d.dispose();// 释放图形上下文使用的系统资源 + return buffImg; + } + + + + private List getPayTypeLocation(int size){ + + if(size == 1){ + return Arrays.asList(new int[]{402, 72}); + } + + if(size == 2){ + return Arrays.asList(new int[]{252, 72}, new int[]{552, 72}); + } + + if(size == 3){ + return Arrays.asList(new int[]{162, 72}, new int[]{402, 72}, new int[]{642, 72}); + } + + if(size == 4){ + return Arrays.asList(new int[]{138, 72}, new int[]{318, 72}, new int[]{513, 72}, new int[]{693, 72}); + } + + if(size == 5){ + return Arrays.asList(new int[]{62, 72}, new int[]{232, 72}, new int[]{402, 72}, new int[]{572, 72}, new int[]{742, 72}); + } + + return null; + } + + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellBGenerator.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellBGenerator.java new file mode 100644 index 0000000..f928c98 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellBGenerator.java @@ -0,0 +1,291 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import com.alibaba.fastjson.JSON; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.*; + +/*** +* ShellC生成器 +* +* @author terrfly +* @date 2023/6/26 15:44 +*/ +@Data +@Service +public class ShellBGenerator extends AbstractGenerator { + + /** 生成二维码图片的 buffer缓冲值 **/ + @Override + public BufferedImage genQrImgBuffer(String configModelStr, String qrUrlContent, Long qrcId, String mchStoreName, boolean isViewFlag) throws IOException, WriterException { + + CommonConfigModel configModel = JSON.parseObject(configModelStr, CommonConfigModel.class); + + String qrId = "No." + qrcId.toString(); + + //图片的宽和高 + int imgWidth = 308 * 3; //924 + int imgHeight = 450 * 3; //1350 + + BufferedImage bufferedImage = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB); + + //设置: 二维码背景颜色 + Graphics2D graphic = bufferedImage.createGraphics(); + graphic.setColor( new Color(Integer.parseInt(StringUtils.defaultIfEmpty(configModel.getBgColor(), "#5094d5").substring(1),16)) );//背景色的设置 + graphic.fillRect(0, 0, imgWidth, imgHeight); + graphic.drawRenderedImage(bufferedImage, null); + + graphic.dispose(); + + + //logo + if(StringUtils.isNotEmpty(configModel.getLogoImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getLogoImgUrl()); + if(imgFile != null){ + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + + graphic.drawImage(waterLogo, 0 , 0, 924, 282, null); + graphic.dispose(); + } + } + + + //设置:二维码背景图 + BufferedImage waterImg = getStaticImg("/shellB/div1.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg, 98, 282, waterImg.getWidth(), waterImg.getHeight(), null); + graphic.dispose(); + + //设置:二维码背景图 + BufferedImage waterImg2 = getStaticImg("/shellB/div2.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg2, 98, 1002, waterImg2.getWidth(), waterImg2.getHeight(), null); + graphic.dispose(); + + + //设置:二维码 190X190 + //生成真实的二维码图片 + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.MARGIN, 1); //调整白边边距 1,2,3,4 四个档位 + BitMatrix bitMatrix = new MultiFormatWriter().encode(qrUrlContent, BarcodeFormat.QR_CODE, 540, 540, hints);// 生成矩阵 + BufferedImage waterQrImg = MatrixToImageWriter.toBufferedImage(bitMatrix); + + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterQrImg, 192, 372, waterQrImg.getWidth(), waterQrImg.getHeight(), null); + graphic.dispose(); + + + //二维码中间logo + if(StringUtils.isNotEmpty(configModel.getQrInnerImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getQrInnerImgUrl()); + if(imgFile != null){ + + + //设置:二维码白框 + BufferedImage waterImg3 = getStaticImg("/shellB/div3.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg3, 417, 597, waterImg3.getWidth(), waterImg3.getHeight(), null); + graphic.dispose(); + + + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterLogo, 422, 602, 80, 80, null); + graphic.dispose(); + } + } + + + + //支付方式 + List> payTypeImgList = new ArrayList<>(); + if(configModel.getPayTypeList() != null){ + for (CommonConfigModel.PayType payType : configModel.payTypeList) { + if("unionpay".equals(payType.getName()) || "ysfpay".equals(payType.getName()) ||"wxpay".equals(payType.getName()) || "alipay".equals(payType.getName()) ){ + payTypeImgList.add(MutablePair.of(payType.getAlias(), getStaticImg("/commons/" + "t_" + payType.getName() + ".png"))); + }else{ + File imgFile = downloadAndGetCacheFile(payType.getImgUrl()); // 下载图片 + if(imgFile != null){ + payTypeImgList.add(MutablePair.of(payType.getAlias(), ImageIO.read(imgFile))); + } + } + } + } + + List areaArrays = getPayTypeLocation(payTypeImgList.size()); + if(areaArrays != null && !areaArrays.isEmpty()){ + for (int i = 0; i < areaArrays.size() ;i++) { + BufferedImage waterImg1 = payTypeImgList.get(i).right; //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg1, areaArrays.get(i)[0], areaArrays.get(i)[1], 60, 60, null); + graphic.dispose(); + + String alias = payTypeImgList.get(i).left; + if(StringUtils.isNotEmpty(alias)){ + + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font font = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 24); + FontMetrics metrics = graphic.getFontMetrics(font); + // 字体居中: 文字中间位置(图标位置+20) - 一半的文字正中间位置 + int x = ( areaArrays.get(i)[0] + 20 ) - (metrics.stringWidth(alias) / 2) + 10; + + graphic.setFont(font); //字体、字型、字号 + graphic.drawString(alias, x, areaArrays.get(i)[1] + 60 + 24 + 16 ); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + + + + } + + + } + } + + if(configModel.isShowIdFlag()){ + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font qrIdFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 27); + FontMetrics metrics = graphic.getFontMetrics(qrIdFont); + int x = (imgWidth - metrics.stringWidth(qrId)) / 2; + + graphic.setFont(qrIdFont); //字体、字型、字号 + graphic.drawString(qrId , x, 955); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + + if(configModel.isShowStoreNameFlag() && StringUtils.isNotEmpty(mchStoreName) ){ + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font qrIdFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 42); + FontMetrics metrics = graphic.getFontMetrics(qrIdFont); + int x = (imgWidth - metrics.stringWidth(mchStoreName)) / 2; + + graphic.setFont(qrIdFont); //字体、字型、字号 + graphic.drawString(mchStoreName , x, 355); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + // 预览需要缩小三倍 + return isViewFlag ? zoomOutImage(bufferedImage, 2) : bufferedImage; + } + + + public static BufferedImage zoomOutImage(BufferedImage originalImage, Integer times){ + + int width = originalImage.getWidth()/times; + if(width < 0){ + width=originalImage.getWidth(); + } + int height = originalImage.getHeight()/times; + if(height < 0){ + height=originalImage.getHeight(); + } + BufferedImage newImage = new BufferedImage(width,height,originalImage.getType()); + + Graphics g = newImage.getGraphics(); + + g.drawImage(originalImage, 0,0,width,height,null); + + g.dispose(); + + return newImage; + + } + + + /** + * + * @Title: 构造图片 + * @Description: 生成水印并返回java.awt.image.BufferedImage + * @param file + * 源文件(图片) + * @param waterFile + * 水印文件(图片) + * @param x + * 距离右下角的X偏移量 + * @param y + * 距离右下角的Y偏移量 + * @param alpha + * 透明度, 选择值从0.0~1.0: 完全透明~完全不透明 + * @return BufferedImage + * @throws IOException + */ + public static BufferedImage watermark(File file, File waterFile, int x, int y, float alpha) throws IOException { + // 获取底图 + BufferedImage buffImg = ImageIO.read(file); + // 获取层图 + BufferedImage waterImg = ImageIO.read(waterFile); + // 创建Graphics2D对象,用在底图对象上绘图 + Graphics2D g2d = buffImg.createGraphics(); + int waterImgWidth = waterImg.getWidth();// 获取层图的宽度 + int waterImgHeight = waterImg.getHeight();// 获取层图的高度 + // 在图形和图像中实现混合和透明效果 + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + // 绘制 + g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null); + g2d.dispose();// 释放图形上下文使用的系统资源 + return buffImg; + } + + + + private List getPayTypeLocation(int size){ + + if(size == 1){ + return Arrays.asList(new int[]{432, 1066}); + } + + if(size == 2){ + return Arrays.asList(new int[]{296, 1066}, new int[]{568, 1066}); + } + + if(size == 3){ + return Arrays.asList(new int[]{207, 1066}, new int[]{432, 1066}, new int[]{657, 1066}); + } + + if(size == 4){ + return Arrays.asList(new int[]{159, 1066}, new int[]{341, 1066}, new int[]{523, 1066}, new int[]{705, 1066}); + } + + return null; + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellCGenerator.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellCGenerator.java new file mode 100644 index 0000000..9ee38c3 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellCGenerator.java @@ -0,0 +1,393 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import com.alibaba.fastjson.JSON; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.*; + +/** +* shellB 图片生成器 +* +* @author terrfly +* @date 2022/1/17 17:36 +*/ +@Data +@Service +public class ShellCGenerator extends AbstractGenerator { + + + /** 图片转换为圆角 **/ + public static BufferedImage setClip(BufferedImage srcImage,int radius){ + + int width = srcImage.getWidth(); + + int height = srcImage.getHeight(); + + BufferedImage image =new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + Graphics2D gs = image.createGraphics(); + + gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + gs.setClip(new RoundRectangle2D.Double(0,0, width, height, radius, radius)); + + gs.drawImage(srcImage,0,0,null); + + gs.dispose(); + + return image; + + } + + + /** 生成二维码图片的 buffer缓冲值 **/ + @Override + public BufferedImage genQrImgBuffer(String configModelStr, String qrUrlContent, Long qrcId, String mchStoreName, boolean isViewFlag) throws IOException, WriterException { + + CommonConfigModel configModel = JSON.parseObject(configModelStr, CommonConfigModel.class); + + String qrId = "No." + qrcId.toString(); + + //图片的宽和高 + int imgWidth = 308 * 3; //924 + int imgHeight = 450 * 3; //1350 + + BufferedImage bufferedImage = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB); + + //设置: 二维码背景颜色 + Graphics2D graphic = bufferedImage.createGraphics(); + graphic.setColor( new Color(Integer.parseInt(StringUtils.defaultIfEmpty(configModel.getBgColor(), "#5094d5").substring(1),16)) );//背景色的设置 + graphic.fillRect(0, 0, imgWidth, imgHeight); + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + + //设置:底部白色背景 + BufferedImage waterImg2 = getStaticImg("/shellC/bg2.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg2, 0, 702, waterImg2.getWidth(), waterImg2.getHeight(), null); + graphic.dispose(); + + //logo + if(StringUtils.isNotEmpty(configModel.getLogoImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getLogoImgUrl()); + if(imgFile != null){ + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + + graphic.drawImage(waterLogo, 0 , 0, 924, 282, null); + graphic.dispose(); + } + } + + + //设置:二维码 190X190 + //生成真实的二维码图片 + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.MARGIN, 0); //调整白边边距 1,2,3,4 四个档位 + BitMatrix bitMatrix = new MultiFormatWriter().encode(qrUrlContent, BarcodeFormat.QR_CODE, 580, 580, hints);// 生成矩阵 + BufferedImage waterQrImg = MatrixToImageWriter.toBufferedImage(bitMatrix); + + + /** ---- 外部圆角矩形 ---- */ + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + + int radiusImgWidth = waterQrImg.getWidth() + 30; + int radiusImgHeight = waterQrImg.getHeight() + 30; + + BufferedImage bufferedImageByOuter = new BufferedImage(radiusImgWidth, radiusImgHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D img2DByOuter = (Graphics2D)bufferedImageByOuter.getGraphics(); + + // 颜色加深20% + Color colorBYOrigin = new Color(Integer.parseInt(StringUtils.defaultIfEmpty(configModel.getBgColor(), "#5094d5").substring(1),16)); + img2DByOuter.setColor( HSLColor.deepen(colorBYOrigin, 20)); + img2DByOuter.fillRect(0, 0, radiusImgWidth, radiusImgHeight); + img2DByOuter.drawRenderedImage(bufferedImageByOuter, null); + img2DByOuter.dispose(); + + bufferedImageByOuter = setClip( bufferedImageByOuter, 20); + + graphic.drawImage(bufferedImageByOuter, 158 , 346, radiusImgWidth, radiusImgHeight, null); + graphic.dispose(); + /** ---- 外部圆角矩形 ---- */ + + /** ---- 内部圆角矩形 ---- */ + + graphic = bufferedImage.createGraphics(); + int radiusImgWidthByInner = waterQrImg.getWidth() + 15; + int radiusImgHeightByInner = waterQrImg.getHeight() + 15; + + BufferedImage bufferedImageByInner = new BufferedImage(radiusImgWidthByInner, radiusImgHeightByInner, BufferedImage.TYPE_INT_RGB); + Graphics2D img2DByInner = (Graphics2D)bufferedImageByInner.getGraphics(); + img2DByInner.setColor( new Color(Integer.parseInt("#FFFFFF".substring(1),16))); + img2DByInner.fillRect(0, 0, radiusImgWidthByInner, radiusImgHeightByInner); + img2DByInner.drawRenderedImage(bufferedImageByInner, null); + img2DByInner.dispose(); + bufferedImageByInner = setClip( bufferedImageByInner, 20); + + graphic.drawImage(bufferedImageByInner, 164 , 354, radiusImgWidthByInner, radiusImgHeightByInner, null); + graphic.dispose(); + + /** ---- 内部圆角矩形 ---- */ + + // 二维码图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterQrImg, 172, 360, waterQrImg.getWidth(), waterQrImg.getHeight(), null); + graphic.dispose(); + + //二维码中间logo + if(StringUtils.isNotEmpty(configModel.getQrInnerImgUrl() )){ + + File imgFile = downloadAndGetCacheFile(configModel.getQrInnerImgUrl()); + if(imgFile != null){ + + //设置:二维码白框 + BufferedImage waterImg3 = getStaticImg("/shellB/div3.png"); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg3, 417, 597, waterImg3.getWidth(), waterImg3.getHeight(), null); + graphic.dispose(); + + + //设置:底部logo + BufferedImage waterLogo = ImageIO.read(imgFile); //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterLogo, 422, 602, 80, 80, null); + graphic.dispose(); + } + } + + + + //支付方式 + List> payTypeImgList = new ArrayList<>(); + if(configModel.getPayTypeList() != null){ + for (CommonConfigModel.PayType payType : configModel.payTypeList) { + if("unionpay".equals(payType.getName()) || "ysfpay".equals(payType.getName()) ||"wxpay".equals(payType.getName()) || "alipay".equals(payType.getName()) ){ + payTypeImgList.add(MutablePair.of(payType.getAlias(), getStaticImg("/commons/" + "t_" + payType.getName() + ".png"))); + }else{ + File imgFile = downloadAndGetCacheFile(payType.getImgUrl()); // 下载图片 + if(imgFile != null){ + payTypeImgList.add(MutablePair.of(payType.getAlias(), ImageIO.read(imgFile))); + } + } + } + } + + List areaArrays = getPayTypeLocation(payTypeImgList.size()); + if(areaArrays != null && !areaArrays.isEmpty()){ + for (int i = 0; i < areaArrays.size() ;i++) { + BufferedImage waterImg1 = payTypeImgList.get(i).right; //水印图片 + graphic = bufferedImage.createGraphics(); + graphic.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1)); //alpha 水印的透明度 0完全透明, 1不透明 + graphic.drawImage(waterImg1, areaArrays.get(i)[0], areaArrays.get(i)[1], 120, 120, null); + graphic.dispose(); + + String alias = payTypeImgList.get(i).left; + if(StringUtils.isNotEmpty(alias)){ + + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font font = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 40); + FontMetrics metrics = graphic.getFontMetrics(font); + // 字体居中: 文字中间位置(图标位置+20) - 一半的文字正中间位置 + int x = ( areaArrays.get(i)[0] + 50 ) - (metrics.stringWidth(alias) / 2) + 10; + + graphic.setFont(font); //字体、字型、字号 + graphic.drawString(alias, x, areaArrays.get(i)[1] + 130 + 24 + 16 ); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + + } + + + } + } + + if(configModel.isShowIdFlag()){ + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font qrIdFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 27); + FontMetrics metrics = graphic.getFontMetrics(qrIdFont); + int x = (imgWidth - metrics.stringWidth(qrId)) / 2; + + graphic.setFont(qrIdFont); //字体、字型、字号 + graphic.drawString(qrId , x, 1005); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + + if(configModel.isShowStoreNameFlag() && StringUtils.isNotEmpty(mchStoreName)){ + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.white);//背景设置为白色 + + Font storeNameFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 58); + FontMetrics metrics = graphic.getFontMetrics(storeNameFont); + int x = (imgWidth - metrics.stringWidth(mchStoreName)) / 2; + + graphic.setFont(storeNameFont); //字体、字型、字号 + graphic.drawString(mchStoreName , x, 270); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + // 预览需要缩小三倍 + return isViewFlag ? zoomOutImage(bufferedImage, 2) : bufferedImage; + } + + + public static BufferedImage zoomOutImage(BufferedImage originalImage, Integer times){ + + int width = originalImage.getWidth()/times; + if(width < 0){ + width=originalImage.getWidth(); + } + int height = originalImage.getHeight()/times; + if(height < 0){ + height=originalImage.getHeight(); + } + BufferedImage newImage = new BufferedImage(width,height,originalImage.getType()); + + Graphics g = newImage.getGraphics(); + + g.drawImage(originalImage, 0,0,width,height,null); + + g.dispose(); + + return newImage; + + } + + + /** + * + * @Title: 构造图片 + * @Description: 生成水印并返回java.awt.image.BufferedImage + * @param file + * 源文件(图片) + * @param waterFile + * 水印文件(图片) + * @param x + * 距离右下角的X偏移量 + * @param y + * 距离右下角的Y偏移量 + * @param alpha + * 透明度, 选择值从0.0~1.0: 完全透明~完全不透明 + * @return BufferedImage + * @throws IOException + */ + public static BufferedImage watermark(File file, File waterFile, int x, int y, float alpha) throws IOException { + // 获取底图 + BufferedImage buffImg = ImageIO.read(file); + // 获取层图 + BufferedImage waterImg = ImageIO.read(waterFile); + // 创建Graphics2D对象,用在底图对象上绘图 + Graphics2D g2d = buffImg.createGraphics(); + int waterImgWidth = waterImg.getWidth();// 获取层图的宽度 + int waterImgHeight = waterImg.getHeight();// 获取层图的高度 + // 在图形和图像中实现混合和透明效果 + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + // 绘制 + g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null); + g2d.dispose();// 释放图形上下文使用的系统资源 + return buffImg; + } + + + + private List getPayTypeLocation(int size){ + + if(size == 1){ + return Arrays.asList(new int[]{402, 1086}); + } + + if(size == 2){ + return Arrays.asList(new int[]{266, 1086}, new int[]{538, 1086}); + } + + if(size == 3){ + return Arrays.asList(new int[]{177, 1086}, new int[]{402, 1086}, new int[]{627, 1086}); + } + + if(size == 4){ + return Arrays.asList(new int[]{77, 1086}, new int[]{294, 1086}, new int[]{510, 1086}, new int[]{727, 1086}); + } + + return null; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellQRGenerator.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellQRGenerator.java new file mode 100644 index 0000000..7fa74f1 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/qrshell/ShellQRGenerator.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.bizcommons.manage.qrshell; + +import com.alibaba.fastjson.JSON; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** +* 仅二维码图片生成器 +* +* @author terrfly +* @date 2022/1/17 17:36 +*/ +@Data +@Service +public class ShellQRGenerator extends AbstractGenerator { + + /** 生成二维码图片的 buffer缓冲值 **/ + @Override + public BufferedImage genQrImgBuffer(String configModelStr, String qrUrlContent, Long qrcId, String mchStoreName, boolean isViewFlag) throws IOException, WriterException { + + String qrId = qrcId.toString(); + + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + BitMatrix bitMatrix = new MultiFormatWriter().encode(qrUrlContent, BarcodeFormat.QR_CODE, 570, 570, hints);// 生成矩阵 + BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix); + + + CommonConfigModel configModel = StringUtils.isNotBlank(configModelStr) ? JSON.parseObject(configModelStr, CommonConfigModel.class) : null; + + // 默认全部显示 二维码ID , 除非明确不显示 + boolean isShowIdFlag = true; + if(configModel != null){ + isShowIdFlag = configModel.showIdFlag; + } + + if(isShowIdFlag){ + + Graphics2D graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//黑色 + //设置:二维码编号 + graphic = bufferedImage.createGraphics(); + graphic.setColor(Color.black);//背景设置为白色 + + Font qrIdFont = new Font(AbstractGenerator.DEFAULT_FONT, Font.PLAIN, 19); + FontMetrics metrics = graphic.getFontMetrics(qrIdFont); + int x = (bufferedImage.getWidth() - metrics.stringWidth(qrcId + "")) / 2; + + graphic.setFont(qrIdFont); //字体、字型、字号 + graphic.drawString(qrId , x, 550); //画文字 + graphic.drawRenderedImage(bufferedImage, null); + graphic.dispose(); + } + + return bufferedImage; + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/sms/SmsManager.java b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/sms/SmsManager.java new file mode 100644 index 0000000..da03e21 --- /dev/null +++ b/jeepay-components/jeepay-components-bizcommons/src/main/java/com/jeequan/jeepay/bizcommons/manage/sms/SmsManager.java @@ -0,0 +1,184 @@ +package com.jeequan.jeepay.bizcommons.manage.sms; + +import cn.hutool.core.util.RandomUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.cache.RedisUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.smsconfig.AbstractSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.MocktestSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizVercodeModel; +import com.jeequan.jeepay.core.sms.ISmsHandler; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import com.jeequan.jeepay.service.impl.SysConfigService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/*** +* 短信相关 +* +* @author terrfly +* @date 2023/8/18 10:05 +*/ +@Component +@Slf4j +public class SmsManager { + + @Autowired private SysConfigService sysConfigService; + + /** 获取短信验证码 **/ + public String genSmsCode(){ + return String.valueOf(RandomUtil.getSecureRandom().nextInt(899999) + 100000); + } + + /** + * 功能描述: 发送短信验证码 (默认5分钟) + * + * @param phoneNo + * @param smsBizType 业务类型 + * @Return: void + * @Author: terrfly + * @Date: 2023/8/18 10:06 + */ + public void sendSmsVercode(String phoneNo, String smsBizType) { + + // 默认 5分钟 + this.sendSmsVercode(phoneNo, smsBizType, 5); + + } + + /** + * 功能描述: 发送短信验证码 + * + * @param phoneNo + * @param smsBizType 业务类型 + * @param expiredMin 过期时间: 分钟 + * @Return: void + * @Author: terrfly + * @Date: 2023/8/18 10:06 + */ + public void sendSmsVercode(String phoneNo, String smsBizType, int expiredMin) { + + // 0. 验证手机号是否正确, 如果不正确将抛业务异常! + if (!AbstractSmsConfig.checkMobileNumber(phoneNo)){ + throw new BizException("手机号格式有误"); + } + + // 1. 获取配置的哪个通道 + MutablePair smsConfigInfo = sysConfigService.getSmsConfigInfo(); + + String smsProviderType = smsConfigInfo.getLeft(); + + // 2. 获取发送短信接口 + ISmsHandler iSmsHandler = SpringBeansUtil.getBean(smsProviderType + "SmsHandler", ISmsHandler.class); + + if(iSmsHandler == null){ + throw new BizException("短信渠道不存在"); + } + + // 3. 生成短信验证码 + AbstractSmsConfig smsConfig = AbstractSmsConfig.getSmsConfig(smsProviderType, smsConfigInfo.getRight()); + + String verifyCode = this.genSmsCode(); + + // mock通道 + if(CS.SMS_PROVIDER_TYPE_API_ENUM.SMS_PROVIDE_KEY_MOCKTEST.equals(smsProviderType)){ + verifyCode = ((MocktestSmsConfig)smsConfig).getMockCode(); + } + + // 4. 构建短信信息 + SmsBizVercodeModel smsVercodeModel = SmsBizVercodeModel.builder() + .phoneNo(phoneNo).smsVercode(verifyCode).smsBizType(smsBizType).expiredMin(expiredMin) + .build(); + + log.info("即将发送手机号:{},短信验证码:{}", phoneNo, verifyCode); + + iSmsHandler.sendVercode(smsVercodeModel, smsConfig); + + // 5. 放置Redis 缓存 短信验证码缓存时间: xx 分钟 + RedisUtil.setString(CS.getCacheKeySmsCode(phoneNo), smsVercodeModel.toJSONString(), expiredMin * 60); + + } + + /** 自定义内容的发送 **/ + public void sendDiyContentSms(SmsBizDiyContentModel smsBizDiyContentModel) { + + try { + + // 0. 验证手机号是否正确, 如果不正确将抛业务异常! + if (!AbstractSmsConfig.checkMobileNumber(smsBizDiyContentModel.getPhoneNo())){ + throw new BizException("手机号格式有误"); + } + + // 1. 获取配置的哪个通道 + MutablePair smsConfigInfo = sysConfigService.getSmsConfigInfo(); + String smsProviderType = smsConfigInfo.getLeft(); + + + // 2. 调用发送短信接口 + ISmsHandler iSmsHandler = SpringBeansUtil.getBean(smsProviderType + "SmsHandler", ISmsHandler.class); + + if(iSmsHandler == null){ + throw new BizException("短信渠道不存在"); + } + + iSmsHandler.sendDiyContent(smsBizDiyContentModel, AbstractSmsConfig.getSmsConfig(smsConfigInfo.getLeft(), smsConfigInfo.getRight())); + + }catch (Exception e){ + log.error("短信发送失败", e); + + } + } + + + /** 判断验证码是否正确 **/ + public void checkSmsVercodeThrowBizEx(String phoneNo, String smsVercode, String smsBizType){ + + String codeJsonStr = RedisUtil.getString(CS.getCacheKeySmsCode(phoneNo)); + if (StringUtils.isEmpty(codeJsonStr)) { + throw new BizException("验证码已过期,请重新点击发送验证码!"); + } + SmsBizVercodeModel smsVercodeModel = JSONObject.parseObject(codeJsonStr, SmsBizVercodeModel.class); + + if(smsVercodeModel == null){ + throw new BizException("验证码已过期,请重新点击发送验证码!"); + } + + if(StringUtils.isEmpty(smsVercodeModel.getSmsVercode()) || !smsVercodeModel.getSmsVercode().equalsIgnoreCase(smsVercode)){ + throw new BizException("验证码错误!"); + } + + if(StringUtils.isEmpty(smsVercodeModel.getSmsBizType()) || !smsVercodeModel.getSmsBizType().equalsIgnoreCase(smsBizType)){ + throw new BizException("验证码类型错误!"); + } + + } + + + /** + * 功能描述: 查询短信相关内容(比如余额等) + * + * @param bizQueryType 查询的业务类型 + * @Return: String + * @Author: yr + * @Date: 2023/8/18 10:06 + */ + public String querySmsInfo(String bizQueryType) { + // 1. 获取配置的哪个通道 + MutablePair smsConfigInfo = sysConfigService.getSmsConfigInfo(); + String smsProviderType = smsConfigInfo.getLeft(); + + // 2. 调用短信查询接口 + ISmsHandler iSmsHandler = SpringBeansUtil.getBean(smsProviderType + "SmsHandler", ISmsHandler.class); + + if(iSmsHandler == null){ + throw new BizException("短信渠道不存在"); + } + return iSmsHandler.querySmsInfo(AbstractSmsConfig.getSmsConfig(smsConfigInfo.getLeft(), smsConfigInfo.getRight()), bizQueryType); + } + +} diff --git a/jeepay-components/jeepay-components-bizcommons/src/test/java/com/.gitkeep b/jeepay-components/jeepay-components-bizcommons/src/test/java/com/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-bizcommons/src/test/resources/.gitkeep b/jeepay-components/jeepay-components-bizcommons/src/test/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-cache/pom.xml b/jeepay-components/jeepay-components-cache/pom.xml new file mode 100644 index 0000000..ab8ba68 --- /dev/null +++ b/jeepay-components/jeepay-components-cache/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + com.jeequan + jeepay-components-cache + jar + ${isys.version} + Jeepay计全支付系统 [jeepay-components-oss] + https://www.jeequan.com + + + com.jeequan + jeepay-components + Final + + + + + ${basedir}/../../ + + + + + + + com.jeequan + jeepay-components-core + + + + + org.springframework + spring-webmvc + provided + + + + + org.slf4j + slf4j-api + + + + + org.springframework.boot + spring-boot + provided + + + + org.springframework.boot + spring-boot-autoconfigure + provided + + + + javax.annotation + javax.annotation-api + provided + + + + + com.aliyun.oss + aliyun-sdk-oss + compile + + + + + + + + src/main/resources + + + src/main/java + **/*.xml + + + + + + diff --git a/jeepay-components/jeepay-components-cache/src/test/java/com/.gitkeep b/jeepay-components/jeepay-components-cache/src/test/java/com/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-cache/src/test/resources/.gitkeep b/jeepay-components/jeepay-components-cache/src/test/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-core/pom.xml b/jeepay-components/jeepay-components-core/pom.xml new file mode 100644 index 0000000..63b87d3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/pom.xml @@ -0,0 +1,172 @@ + + + 4.0.0 + + com.jeequan + jeepay-components-core + jar + ${isys.version} + Jeepay计全支付系统 [jeepay-core] + https://www.jeequan.com + + + com.jeequan + jeepay-components + Final + + + + + ${basedir}/../../ + + + + + + + p6spy + p6spy + + + + + org.springframework + spring-context + provided + + + + + org.springframework.boot + spring-boot-starter-data-redis + provided + + + + + org.springframework + spring-webmvc + provided + + + + javax.servlet + javax.servlet-api + provided + + + + + com.baomidou + mybatis-plus-boot-starter + + + + com.baomidou + mybatis-plus-extension + + + + + io.jsonwebtoken + jjwt + provided + + + + + org.springframework.security + spring-security-core + provided + + + + + com.alibaba + fastjson + + + + + org.apache.commons + commons-lang3 + + + + + com.aliyun + aliyun-java-sdk-core + provided + + + + com.aliyun + aliyun-java-sdk-dysmsapi + provided + + + + + org.hibernate.validator + hibernate-validator + provided + + + + + cn.afterturn + easypoi-base + + + cn.afterturn + easypoi-web + + + cn.afterturn + easypoi-annotation + + + + org.springframework.boot + spring-boot-starter-mail + + + + org.springframework.boot + spring-boot-starter-test + + + com.alipay.sdk + alipay-sdk-java + + + + + + + + src/main/resources + + + src/main/java + **/*.xml + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + + java,class + + + + + + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/ChannelMchId.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/ChannelMchId.java new file mode 100644 index 0000000..9b5dc62 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/ChannelMchId.java @@ -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(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/Desensitized.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/Desensitized.java new file mode 100644 index 0000000..26b6f49 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/Desensitized.java @@ -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(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/ChannelMchIdKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/ChannelMchIdKit.java new file mode 100644 index 0000000..65369cc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/ChannelMchIdKit.java @@ -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]; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/DesenKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/DesenKit.java new file mode 100644 index 0000000..f94369e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/annotate/kits/DesenKit.java @@ -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 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 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; + } + } + } + } + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/aop/MethodLog.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/aop/MethodLog.java new file mode 100644 index 0000000..1a475b6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/aop/MethodLog.java @@ -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 ""; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/beans/RequestKitBean.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/beans/RequestKitBean.java new file mode 100644 index 0000000..c8fb315 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/beans/RequestKitBean.java @@ -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 properties = request.getParameterMap(); + for (Map.Entry 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; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/ITokenService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/ITokenService.java new file mode 100644 index 0000000..7faab7a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/ITokenService.java @@ -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 allTokenList = new ArrayList<>(); +// for (String token : allTokenList) { +// if(!cacheKey.equalsIgnoreCase(token)){ +// RedisUtil.del(token); +// } +// } +// } + + //当前用户的所有登录token 集合 + List 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; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/RedisUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/RedisUtil.java new file mode 100644 index 0000000..483278a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/cache/RedisUtil.java @@ -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 getObject(String key, Class 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 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 keys = redisTemplate.keys(getRealKey(keyPrefix) + "*"); + if (CollUtil.isEmpty(keys)) { + return; + } + + for (String key : keys) { + redisTemplate.delete(key); + } + } + + /** 查询keys */ + public static Collection keys(String pattern) { + + Collection queryResult = getStringRedisTemplate().keys(RedisUtil.getRealKey(pattern)); + if(queryResult == null || queryResult.isEmpty()){ + return queryResult; + } + + // 转换为: 业务的key + Collection 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); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/FilterConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/FilterConfig.java new file mode 100644 index 0000000..35fc928 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/FilterConfig.java @@ -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 customFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new URIFilter()); + registrationBean.addUrlPatterns("/*"); // 设置要过滤的 URL 模式 + registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置为最高优先级 + return registrationBean; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/SpySqlFormatConfigure.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/SpySqlFormatConfigure.java new file mode 100644 index 0000000..8f8eba0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/SpySqlFormatConfigure.java @@ -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 { + + /** + *

输出执行sql信息

+ * @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 ""; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/URIFilter.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/URIFilter.java new file mode 100644 index 0000000..f13e363 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/URIFilter.java @@ -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()方法已足够 +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/WebConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/WebConfig.java new file mode 100644 index 0000000..50f8a03 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/config/WebConfig.java @@ -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()); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ApiCodeEnum.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ApiCodeEnum.java new file mode 100644 index 0000000..bbe863d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ApiCodeEnum.java @@ -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; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/CS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/CS.java new file mode 100644 index 0000000..9fc5ea9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/CS.java @@ -0,0 +1,720 @@ +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 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 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 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 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 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; + } + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ChannelMchIdTypeEnum.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ChannelMchIdTypeEnum.java new file mode 100644 index 0000000..5d270cf --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ChannelMchIdTypeEnum.java @@ -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, + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ConstWord.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ConstWord.java new file mode 100644 index 0000000..56dae3a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/ConstWord.java @@ -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"; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/DesensitizedTypeEnum.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/DesensitizedTypeEnum.java new file mode 100644 index 0000000..cffa173 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/constants/DesensitizedTypeEnum.java @@ -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 + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/ctrls/AbstractCtrl.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/ctrls/AbstractCtrl.java new file mode 100644 index 0000000..71da24d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/ctrls/AbstractCtrl.java @@ -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 Page getIPage() { + return new Page<>(getPageIndex(), getPageSize()); + } + + /** + * 获取Ipage分页信息, 加入条件:是否允许获取全部数据 + **/ + protected Page getIPage(boolean allowQueryAll) { + return new Page<>(getPageIndex(), getPageSize(allowQueryAll)); + } + + /** + * 获取排序字段 MutablePair<是否正序, 排序字段> + **/ + protected MutablePair 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 getVal(String key, Class cls) { + return getReqParamJSON().getObject(key, cls); + } + + /** + * 获取请求参数值 [ T 类型 ], [ 必填 ] + **/ + protected T getValRequired(String key, Class cls) { + T value = getVal(key, cls); + if (ObjectUtils.isEmpty(value)) { + throw new BizException(ApiCodeEnum.PARAMS_ERROR, genParamRequiredMsg(key)); + } + return value; + } + + /** + * 获取请求参数值 [ T 类型 ], [ 如为null返回默认值 ] + **/ + protected T getValDefault(String key, T defaultValue, Class 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 getObject(Class clazz) { + + JSONObject params = getReqParamJSON(); + T result = params.toJavaObject(clazz); + + if (result instanceof BaseModel) { //如果属于BaseModel, 处理apiExtVal + JSONObject resultTemp = (JSONObject) JSON.toJSON(result); + for (Map.Entry 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 request2payResponseMap(HttpServletRequest request, String[] paramArray) { + Map 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(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountCashInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountCashInfo.java new file mode 100644 index 0000000..afda997 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountCashInfo.java @@ -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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountOperate.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountOperate.java new file mode 100644 index 0000000..2f45c79 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountOperate.java @@ -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("金额不能为空"); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountRuleExt.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountRuleExt.java new file mode 100644 index 0000000..7bc692b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/AccountRuleExt.java @@ -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 typeList; + + /** + * 接收人信息 + */ + private List receiveList; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CashoutRecord.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CashoutRecord.java new file mode 100644 index 0000000..6bc0af0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CashoutRecord.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/ChannelAccountCashoutRecord.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/ChannelAccountCashoutRecord.java new file mode 100644 index 0000000..821e29d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/ChannelAccountCashoutRecord.java @@ -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; + +/** + *

+ * 提现结算记录表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CheckBatch.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CheckBatch.java new file mode 100644 index 0000000..6649c5e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/CheckBatch.java @@ -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; + +/** + *

+ * 对账批次表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvInfo.java new file mode 100644 index 0000000..698aa31 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvInfo.java @@ -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; + +/** + *

+ * 服务商信息表 + *

+ * + * @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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvUserConn.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvUserConn.java new file mode 100644 index 0000000..68853d2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/IsvUserConn.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApp.java new file mode 100644 index 0000000..71190dd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApp.java @@ -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; + +/** + *

+ * 商户应用表 + *

+ * + * @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 capabilities; + + /** + * 开通需求 + */ + private List preCapabilities; + /** + * 是否开通轮询 + */ + private String turnsPay; + + /** + * 0: 线下, + * 1: 线上 + * 2: 专属 + */ + private Integer range; + + /** + * 是否支持API, + * 0: 不支持 + * 1: 支持 + */ + private Integer apiFlag; + + /** + * 应用的功能code,前端保存的时候传递该参数 + */ + private List capabilityCodeList; + + /** + * 应用信息 + */ + private List information; + + private String mccCode; + + private List qualificationList; + + /** + * 预开通的方案 + */ + private String predicOpenPackage; + + /** + * 预开通的产品 + */ + private String predicOpenProduct; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApplyment.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApplyment.java new file mode 100644 index 0000000..ad43448 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchApplyment.java @@ -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; + +/** + *

+ * 特约商户进件信息表 + *

+ * + * @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; + + /** + * 反扫权限开关。1:开;0:关;2:未指定,根据业务判断是否开关 + * 为空同2 + */ + private Integer scanPayPerm; + + public boolean scanPayPermFlag(Function 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); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchDivisionReceiver.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchDivisionReceiver.java new file mode 100644 index 0000000..eaff302 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchDivisionReceiver.java @@ -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; + +/** + *

+ * 商户分账接收者账号绑定关系表 + *

+ * + * @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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchInfo.java new file mode 100644 index 0000000..7d8b9ef --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchInfo.java @@ -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; + +/** + *

+ * 商户信息表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchModifyApplyment.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchModifyApplyment.java new file mode 100644 index 0000000..a57fe6f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchModifyApplyment.java @@ -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; + +/** + *

+ * 特约商户进件信息表 + *

+ * + * @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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStore.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStore.java new file mode 100644 index 0000000..e7c085a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStore.java @@ -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; + +/** + *

+ * 商户门店表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreDevice.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreDevice.java new file mode 100644 index 0000000..08142b0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreDevice.java @@ -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; + +/** + *

+ * 商户门店设备配置表 + *

+ * + * @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 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 carouselPicInfo; + + /** + * 付款区域背景图 + */ + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject payPicInfo; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreTerminal.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreTerminal.java new file mode 100644 index 0000000..c298f23 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchStoreTerminal.java @@ -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; + +/** + *

+ * 商户辅助终端信息报备表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchSubInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchSubInfo.java new file mode 100644 index 0000000..f77aa74 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchSubInfo.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoAuth.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoAuth.java new file mode 100644 index 0000000..830bf51 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoAuth.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoCache.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoCache.java new file mode 100644 index 0000000..7350e9f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchVideoCache.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchWxmpUser.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchWxmpUser.java new file mode 100644 index 0000000..f42cb0a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/MchWxmpUser.java @@ -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; + +/** + *

+ * 商户公众号消息接收用户列表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java new file mode 100644 index 0000000..28f79ac --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrder.java @@ -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; + +/** + *

+ * 支付订单表 + *

+ * + * @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-扫码POS,auto_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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderCount.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderCount.java new file mode 100644 index 0000000..c1d534e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderCount.java @@ -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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRecord.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRecord.java new file mode 100644 index 0000000..b9b4897 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRecord.java @@ -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; + +/** + *

+ * 分账记录表 + *

+ * + * @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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRefundRecord.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRefundRecord.java new file mode 100644 index 0000000..cc9ad45 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/PayOrderDivisionRefundRecord.java @@ -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; + +/** + *

+ * 分账记录表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/RefundOrder.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/RefundOrder.java new file mode 100644 index 0000000..2f5cf10 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/RefundOrder.java @@ -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; + +/** + *

+ * 退款订单表 + *

+ * + * @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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/SysUser.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/SysUser.java new file mode 100644 index 0000000..f2989a7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/SysUser.java @@ -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; + +/** + *

+ * 系统用户表 + *

+ * + * @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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferOrder.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferOrder.java new file mode 100644 index 0000000..1391f3c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferOrder.java @@ -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; + +/** + *

+ * 转账订单表 + *

+ * + * @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; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferSubject.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferSubject.java new file mode 100644 index 0000000..ea2fbca --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferSubject.java @@ -0,0 +1,262 @@ +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; + +/** + *

+ * 转账对象表 + *

+ * + * @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; + + /** + * 商户号 + */ + 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; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferWallet.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/entity/TransferWallet.java new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/AccessMsgException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/AccessMsgException.java new file mode 100644 index 0000000..057d9f7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/AccessMsgException.java @@ -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; + } + +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizException.java new file mode 100644 index 0000000..1ef8311 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizException.java @@ -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; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizExceptionResolver.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizExceptionResolver.java new file mode 100644 index 0000000..7231b4c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/BizExceptionResolver.java @@ -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(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ChannelException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ChannelException.java new file mode 100644 index 0000000..8e90069 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ChannelException.java @@ -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)); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/JeepayAuthenticationException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/JeepayAuthenticationException.java new file mode 100644 index 0000000..9026f86 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/JeepayAuthenticationException.java @@ -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; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ResponseException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ResponseException.java new file mode 100644 index 0000000..e1e2cff --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/ResponseException.java @@ -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); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/openapi/ParamException.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/openapi/ParamException.java new file mode 100644 index 0000000..99328c1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/exception/openapi/ParamException.java @@ -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); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interceptor/ReqInfoInterceptor.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interceptor/ReqInfoInterceptor.java new file mode 100644 index 0000000..6ba4caf --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interceptor/ReqInfoInterceptor.java @@ -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 headerNames = httpServletRequest.getHeaderNames(); + Map 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 getParameterInfo(HttpServletRequest request) { + Map parameter = new HashMap<>(); + Map parameterMap = request.getParameterMap(); + + for (Map.Entry 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; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IBizOrderQueryService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IBizOrderQueryService.java new file mode 100644 index 0000000..0234739 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IBizOrderQueryService.java @@ -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 queryPayOrderRefundDivisionRefundRecordList(RefundOrder refundOrder, PayOrder payOrder); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/ICodeSysTypeManager.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/ICodeSysTypeManager.java new file mode 100644 index 0000000..fd2667a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/ICodeSysTypeManager.java @@ -0,0 +1,9 @@ +package com.jeequan.jeepay.core.interfaces; + +/** 当前项目类型管理 **/ +public interface ICodeSysTypeManager { + + /** 获取当前项目名称(全大写形式) **/ + String getCodeSysName(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextQueryService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextQueryService.java new file mode 100644 index 0000000..8315b5f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextQueryService.java @@ -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 queryIsvParams(MchApplyment mchApplyment); + + Oauth2Params queryIsvOauth2Params(String isvNo, String ifCode); + + Oauth2Params queryNormalOauth2Params(String mchNo, String mchAppId, String ifCode); + + T queryOauth2Params(String infoType, String infoId, String ifCode, Class cls); + + /** + * 新版获取接口 + * + * @param mchNo 商户号 + * @return + */ + MchAppConfigContext queryMchInfoAndAppInfoV2(String mchNo, String mchAppId, String applyId); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextService.java new file mode 100644 index 0000000..413e2f2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IConfigContextService.java @@ -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); + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IOCRApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IOCRApiService.java new file mode 100644 index 0000000..33965ee --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/IOCRApiService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/bill/IReconciliationService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/bill/IReconciliationService.java new file mode 100644 index 0000000..75641a0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/bill/IReconciliationService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/cashout/IChannelCashoutNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/cashout/IChannelCashoutNoticeService.java new file mode 100644 index 0000000..2796072 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/cashout/IChannelCashoutNoticeService.java @@ -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 parseParams(HttpServletRequest request, String rid); + + /** 返回需要更新的提现状态 和响应数据 **/ + CashoutRetMsg doNotice(HttpServletRequest request, + Object params, ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/IPrinterService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/IPrinterService.java new file mode 100644 index 0000000..05ee834 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/IPrinterService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/ISpeakerService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/ISpeakerService.java new file mode 100644 index 0000000..4f4eee8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/device/ISpeakerService.java @@ -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; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentApiService.java new file mode 100644 index 0000000..911e407 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentApiService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentResourceService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentResourceService.java new file mode 100644 index 0000000..bc30763 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IApplymentResourceService.java @@ -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 getBankCode(IPage iPage, JSONObject queryParams); + + /** 获取省市编码 **/ + List getAreaCode(IsvParams isvParams, JSONObject reqParams); + + /** type 自定义业务种类 获取商户号和json数据对象进行特定操作 **/ + String sendPubRequst(String type, String mchNo, String applyId, String jsonStr); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IBillDownloadService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IBillDownloadService.java new file mode 100644 index 0000000..69d40f2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IBillDownloadService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelAccountService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelAccountService.java new file mode 100644 index 0000000..fcd2d27 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelAccountService.java @@ -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 queryBalanceAmount(MchAppConfigContext mchAppConfigContext, String ifCode); + + /** 账户提现 **/ + CashoutRetMsg cashout(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode); + + /** 账户提现查询 **/ + CashoutRetMsg cashoutQuery(ChannelAccountCashoutRecord cashoutRecord, MchAppConfigContext mchAppConfigContext, String ifCode); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelNoticeService.java new file mode 100644 index 0000000..780191a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelNoticeService.java @@ -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 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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelOrderAcceptService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelOrderAcceptService.java new file mode 100644 index 0000000..9a4d404 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelOrderAcceptService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelRefundNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelRefundNoticeService.java new file mode 100644 index 0000000..ee45628 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelRefundNoticeService.java @@ -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 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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelUserService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelUserService.java new file mode 100644 index 0000000..51f679a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IChannelUserService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDgApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDgApplymentApiService.java new file mode 100644 index 0000000..cb79df8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDgApplymentApiService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDivisionService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDivisionService.java new file mode 100644 index 0000000..6fa9987 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IDivisionService.java @@ -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 recordList, MchAppConfigContext mchAppConfigContext); + + /** 查询分账结果 **/ + HashMap queryDivision(PayOrder payOrder, List 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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IFuiouApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IFuiouApplymentApiService.java new file mode 100644 index 0000000..7432add --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IFuiouApplymentApiService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IGetApplymentDataService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IGetApplymentDataService.java new file mode 100644 index 0000000..a508863 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IGetApplymentDataService.java @@ -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 getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode, String bankName, String branchName) throws BizException { + return new ArrayList<>(); + } + + default List getBankBranchInfo(String isvNo, String bankAliasCode, String cityCode) throws BizException { + return new ArrayList<>(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchAlipayConfigService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchAlipayConfigService.java new file mode 100644 index 0000000..c6bc91b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchAlipayConfigService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentNotifyService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentNotifyService.java new file mode 100644 index 0000000..6bbc68f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentNotifyService.java @@ -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 parseParams(HttpServletRequest request, String urlApplyId); + + /** + * 返回需要更新的订单状态 和响应数据 (验签等操作) + * @param request + * @param params 解密后的回调参数 + * @param mchApplyment 商户信息, 必须包含完整的数据 + * @return + */ + MutablePair doNotify(HttpServletRequest request, Object params, MchApplyment mchApplyment); + + default ResponseEntity retOk(Object params) { + return ResponseEntity.ok(params); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentService.java new file mode 100644 index 0000000..0219439 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchApplymentService.java @@ -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 { + + 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 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) { + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchModifyApplymentService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchModifyApplymentService.java new file mode 100644 index 0000000..074c77c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchModifyApplymentService.java @@ -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 localModifyBase(MutablePair mchDataPair); + + /** + * 本地结算信息变更 + */ + MutablePair localModifySettlement(MutablePair mchDataPair); + + /** + * 本地结算信息变更 + */ + MutablePair localModifyRate(MutablePair mchDataPair); + + + default MutablePair localModifySettlementType(MutablePair 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 syncChannelModifyBase(MutablePair mchDataPair); + + /** + * 结算信息变更, 上游通道同步 + */ + MutablePair syncChannelModifySettlement(MutablePair mchDataPair); + + /** + * 费率变更, 上游通道同步 + */ + MutablePair syncChannelModifyRate(MutablePair mchDataPair); + + /** + * 结算方式变更,上游通道同步 + * + */ + MutablePair syncChannelModifySettlementType(MutablePair mchDataPair); + + MutablePair queryModifyResult(MutablePair mchDataPair); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentNotifyService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentNotifyService.java new file mode 100644 index 0000000..322f291 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentNotifyService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentService.java new file mode 100644 index 0000000..04f264b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchStoreApplymentService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchTerminalService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchTerminalService.java new file mode 100644 index 0000000..2c24625 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchTerminalService.java @@ -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日,中国人民银行发布了《中国人民银行关于加强支付受理终端及相关业务管理的通知》(银发〔2021〕259号,以下简称《通知》),自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); + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWrapper.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWrapper.java new file mode 100644 index 0000000..bb7c0e0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWrapper.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWxConfigService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWxConfigService.java new file mode 100644 index 0000000..5b86f9c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IIsvmchWxConfigService.java @@ -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 paywayFeeList, String isvNo, String mchNo, String mchAppId, String ifCode); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ILeshuaApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ILeshuaApplymentApiService.java new file mode 100644 index 0000000..ad2de47 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ILeshuaApplymentApiService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchApiService.java new file mode 100644 index 0000000..48774fb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchApiService.java @@ -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 { + + /** 获取到接口code **/ + String getIfCode(); + + /** + * 前置参数校验 + * @return + */ + boolean preCheck(); + + /** + * appid和支付授权目录相关操作 + * @param applyment + * @param mchRq + * @return + */ + ChannelRetMsg appidAndPath(MchApplyment applyment, ChannelMchRq mchRq); + + /** + * 查询商户结算记录 + * @param settleRq + * @return + */ + List querySettleInfo(ChannelSettleRq settleRq, String isvNo, T isvParams); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchAutoAuthService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchAutoAuthService.java new file mode 100644 index 0000000..2137199 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IMchAutoAuthService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderCloseService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderCloseService.java new file mode 100644 index 0000000..190c2fc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderCloseService.java @@ -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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderQueryService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderQueryService.java new file mode 100644 index 0000000..fe08618 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderQueryService.java @@ -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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderSettService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderSettService.java new file mode 100644 index 0000000..7b6344c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPayOrderSettService.java @@ -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); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPaymentService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPaymentService.java new file mode 100644 index 0000000..bf47df8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPaymentService.java @@ -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; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPosNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPosNoticeService.java new file mode 100644 index 0000000..aa5db82 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IPosNoticeService.java @@ -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 parseParams(HttpServletRequest request); + + /** 返回需要插入的支付订单金额 和响应数据 **/ + ChannelRetMsg payNotice(HttpServletRequest request, Object params, PayOrder payOrder, MchAppConfigContext mchAppConfigContext); + + /** 返回需要插入的退款订单金额 和响应数据 **/ + ChannelRetMsg refundNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRefundService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRefundService.java new file mode 100644 index 0000000..bf2849e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRefundService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayApiService.java new file mode 100644 index 0000000..6605418 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayApiService.java @@ -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); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayNoticeService.java new file mode 100644 index 0000000..797b319 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IRepayNoticeService.java @@ -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 parseParams(HttpServletRequest request, String urlOrderId); + + /** 处理参数业务逻辑 **/ + ChannelRetMsg doNotice(HttpServletRequest request,String urlOrderId,Object params); + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ISqbApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ISqbApiService.java new file mode 100644 index 0000000..77609b0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ISqbApiService.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.interfaces.paychannel; + +import com.alibaba.fastjson.JSONObject; + +/** + * 收钱吧 接口 + * + * @author xiaoyu + * + * @date 2022/6/9 9:26 + */ +public interface ISqbApiService { + + /** 激活终端 **/ + JSONObject activation(JSONObject params); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferNoticeService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferNoticeService.java new file mode 100644 index 0000000..5fa9379 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferNoticeService.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.core.interfaces.paychannel; + +import com.jeequan.jeepay.core.entity.TransferOrder; +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; + +/* +* 转账订单通知解析实现 异步回调 +* +* @author zx +* +* @date 2022/12/30 10:14 +*/ +public interface ITransferNoticeService { + + /** 获取到接口code **/ + String getIfCode(); + + /** 解析参数: 转账单号 和 请求参数 + * 异常需要自行捕捉,并返回null , 表示已响应数据。 + * **/ + MutablePair parseParams(HttpServletRequest request, String urlOrderId); + + /** 返回需要更新的订单状态 和响应数据 **/ + ChannelRetMsg doNotice(HttpServletRequest request, + Object params, TransferOrder transferOrder); + + /** 数据库订单数据不存在 (仅异步通知使用) **/ + ResponseEntity doNotifyOrderNotExists(HttpServletRequest request); + + default Object retOk(Object param) { + return "SUCCESS"; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferService.java new file mode 100644 index 0000000..1328128 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/ITransferService.java @@ -0,0 +1,96 @@ +package com.jeequan.jeepay.core.interfaces.paychannel; + +import com.jeequan.jeepay.core.beans.RequestKitBean; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.entity.TransferWallet; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.openapi.biz.transfer.TransferOrderParam; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import com.jeequan.jeepay.core.utils.SeqKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.MutablePair; + +import java.util.Date; + +/** +* 转账接口 +* +* @author terrfly +* +* @date 2021/8/11 13:59 +*/ +public interface ITransferService { + + /* 获取到接口code **/ + String getIfCode(); + + /** 是否支持该支付入账方式 */ + boolean isSupport(String entryType); + + PaywayFee paywayFee(TransferOrderParam bizRQ, TransferOrder transferOrder); + + default TransferOrder genTransferOrder(TransferOrderParam rq, TransferSubject transferSubject, + TransferWallet wallet, String ifCode){ + + TransferOrder transferOrder = new TransferOrder(); + transferOrder.setTransferId(SeqKit.genTransOrderId()); //生成转账订单号 + transferOrder.setTransferSubjectIdFq(rq.getTransferFqId()); //生成转账订单号 + transferOrder.setMchNo(transferSubject.getMchNo()); //商户号 + transferOrder.setIsvNo(transferSubject.getIsvNo()); //服务商号 + transferOrder.setWalletId(wallet.getId()); + transferOrder.setAgentNo(transferSubject.getAgentNo()); // 服务商号 + transferOrder.setAppId(transferSubject.getAppId()); //商户应用appId + transferOrder.setMchOrderNo(rq.getMchOrderNo()); //商户订单号 + transferOrder.setIfCode(ifCode); //接口代码 + transferOrder.setEntryType(rq.getEntryType()); //入账方式 + transferOrder.setAmount(rq.getAmount()); //订单金额 + transferOrder.setCurrency(rq.getCurrency()); //币种 + + RequestKitBean requestKitBean = SpringBeansUtil.getBean(RequestKitBean.class); + transferOrder.setClientIp(StringUtils.defaultIfEmpty(rq.getClientIp(), requestKitBean.getClientIp())); //客户端IP + transferOrder.setState(TransferOrder.STATE_INIT); //订单状态, 默认订单生成状态 + transferOrder.setAccountNo(rq.getAccountNo()); //收款账号 + transferOrder.setOriginAccountName(transferSubject.getAccountName()); + transferOrder.setOriginAccountNo(transferSubject.getAccount()); + transferOrder.setAccountName(rq.getAccountName()); //账户姓名 + transferOrder.setAccountType(rq.getAccountType()); + transferOrder.setBankName(rq.getBankName()); //银行名称 + transferOrder.setTransferDesc(rq.getTransferDesc()); //转账备注 + transferOrder.setExtParam(rq.getExtParam()); //商户扩展参数 + transferOrder.setNotifyUrl(rq.getNotifyUrl()); //异步通知地址 + transferOrder.setTransferType(TransferOrder.TRANSFER_TYPE_DF); + + PaywayFee paywayFee = paywayFee(rq, transferOrder); + + // 转账手续费, 可以为空。 + if(paywayFee != null){ + MutablePair feeAndSnapshot = paywayFee.calFeeAndSnapshot(transferOrder.getAmount()); + transferOrder.setMchFeeRate(feeAndSnapshot.left); + transferOrder.setMchOrderFeeAmount(feeAndSnapshot.right); //商户手续费,单位分 + } + + transferOrder.setCreatedAt(new Date()); //订单创建时间 + return transferOrder; + + } + + /** 通用校验,一般来说全部通道都需要进行该校验 */ + void commonCheck(TransferOrderParam bizRQ, TransferOrder transferOrder); + + /** 前置检查如参数等信息是否符合要求, 返回错误信息或直接抛出异常即可 */ + String preCheck(TransferOrderParam bizRQ, TransferOrder transferOrder); + + + /** 调起转账接口,并响应数据; 内部处理普通商户和服务商模式 **/ + ChannelRetMsg transfer(TransferOrderParam bizRQ, TransferOrder transferOrder) throws Exception; + + /** 调起转账查询接口 **/ + ChannelRetMsg query(TransferOrder transferOrder, IsvParams isvParams); + + /** 查询分账账户余额 **/ + MutablePair queryBalanceAmount(TransferWallet transferWallet); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IUtmpayApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IUtmpayApplymentApiService.java new file mode 100644 index 0000000..fa36be1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IUtmpayApplymentApiService.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.core.interfaces.paychannel; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; + +/*** +* 商户进件配置接口 +* +* @author terrfly +* +* @date 2021/12/30 11:36 +*/ +public interface IUtmpayApplymentApiService { + + ChannelRetMsg getMchPartner(String apiCode, String isvNo, String mchNo, String mchAppId); + + ChannelRetMsg mchPayConfAdd(JSONObject configJSON, String isvNo, String mchNo, String mchAppId); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IYsApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IYsApplymentApiService.java new file mode 100644 index 0000000..8fbd6dd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IYsApplymentApiService.java @@ -0,0 +1,51 @@ +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.MchModifyApplyment; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; + +/*** +* 商户进件接口 +* +* @author terrfly +* +* @date 2021/12/30 11:36 +*/ +public interface IYsApplymentApiService { + + /** 图片上传 **/ + MchApplyment uploadImg(MchApplyment mchApplyment); + + /** 提交审核 **/ + MchApplyment attachConfirm(MchApplyment mchApplyment); + + /** 合同签约申请 **/ + MchApplyment signApply(JSONObject reqParamJSON, MchApplyment mchApplyment); + + /** + * 签约重发 + **/ + MchApplyment signSendAgain(JSONObject reqParamJSON, MchApplyment mchApplyment); + + /** 合同签约查询 **/ + MchApplyment signQuery(MchApplyment dbRecord); + + /** + * 签约重发 + **/ + MchModifyApplyment signSendAgain(JSONObject reqParamJSON, MchModifyApplyment modifyApplyment); + + /** 支付费率配置 **/ + MchApplyment payRateConfig(JSONObject reqParamJSON, MchApplyment mchApplyment); + + /** 绑定微信appId **/ + ChannelRetMsg configBindAppId(String configVal, String mchAppId, MchApplyment mchApplyment); + + /** 设置关注公众号appId **/ + ChannelRetMsg configSubscribeAppId(String configVal, String mchAppId, MchApplyment mchApplyment); + + /** 设置微信 支付授权目录 **/ + ChannelRetMsg configPayBaseUrl(String configVal, String mchAppId, MchApplyment mchApplyment); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IZftApplymentApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IZftApplymentApiService.java new file mode 100644 index 0000000..c2c694a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/IZftApplymentApiService.java @@ -0,0 +1,18 @@ +package com.jeequan.jeepay.core.interfaces.paychannel; + +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; + +/** + * 支付宝直付通进件相关接口 + * + * @author xiaoyu + * + * @date 2023/10/23 15:12 + */ +public interface IZftApplymentApiService { + + /** 商户号作废接口 **/ + ChannelRetMsg zftMchDelete(MchInfo mchInfo, String smId); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliAqfV2ApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliAqfV2ApiService.java new file mode 100644 index 0000000..b2a3504 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliAqfV2ApiService.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.core.interfaces.paychannel.aliaqfbiz; + + +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.response.AlipayFundAccountbookQueryResponse; +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; + +/** + * 安全发接口服务类 + */ +public interface IAliAqfV2ApiService { + /** + * 签约 + */ + String userAgreementPageSign(String infoId); + + /** + * 支付宝个人代扣协议查询 + */ + JSONObject userAgreementQuery(String subId); + + /** + * 解约 + */ + JSONObject userAgreementUnsign(String subId); + + /** + * 资金记账本开通 + * @param + * @return + */ + void fundAccountbookCreate(String subId); + + /** + * 资金记账本的信息查询 + * @return + */ + AlipayFundAccountbookQueryResponse fundAccountbookQuery(String walletApplyId); + + /** + * 资金专款拨入(商户自身给记账本充值) + * @return + */ + String transPage(String subId,String transAmount ,String transferDesc); + + /** + * 代发 + * @return + */ + ChannelRetMsg transUniTransfer(TransferOrder transferOrder); + + /** + * 账单查询 + * @return + */ + JSONObject bizfundagentQuery( String ersubId, String startTime, String endTime, String pageNo, String pageSize); + + /** + * 申请电子回单 + * @return + */ + JSONObject applicationForm(String ersubId,String transferId); + + /** + * 电子回单下载地址获取 + * @return + */ + JSONObject applicationFormDownload(String ersubId,String transferId); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliaqfApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliaqfApiService.java new file mode 100644 index 0000000..e801333 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/aliaqfbiz/IAliaqfApiService.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.core.interfaces.paychannel.aliaqfbiz; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; + +/* + * 支付宝安全发API接口 + * + * @author xiaoyu + * + * @date 2023/4/3 9:52 + */ +public interface IAliaqfApiService { + + /** 获取支付宝个人协议页面签约接口 **/ + String userAgreementPageSign(AliaqfIsvParams aliaqfIsvParams, String appId); + + /** 查询支付宝个人协议页面签约接口 **/ + String queryUserAgreementPageSign(AliaqfIsvParams ALIAQFIsvParams, String appId); + + /** 资金记账本开通接口 **/ + String fundAccountbookCreate(AliaqfIsvParams ALIAQFIsvParams, String appId, String mchNo, String agreementNo); + + /** 资金转账页面接口 **/ + String fundTransPage(AliaqfIsvParams ALIAQFIsvParams, String appId, String mchNo, Long transAmount); + + /** 记账本信息查询接口 **/ + JSONObject fundAccountbookQuery(MchAppConfigContext mchAppConfigContext); + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayIotDeviceBindService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayIotDeviceBindService.java new file mode 100644 index 0000000..4363294 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayIotDeviceBindService.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; + +/* +* 蚂蚁店铺接口 +* +* @author zx +* +* @date 2023/3/14 15:13 +*/ +public interface IAlipayIotDeviceBindService { + + /** Iot设备-商户-店铺绑定 **/ + void bind(AlipayIsvParams alipayIsvParams, String mchNo, String alipayMerchantNo, String alipayShopId, String supplierId, JSONObject deviceJSON); + + /** Iot设备-商户-店铺解绑 **/ + void unbind(AlipayIsvParams alipayIsvParams, String mchNo, String alipayMerchantNo, String alipayShopId, String supplierId, String deviceSn); + + /** Iot设备-商户-店铺绑定查询 **/ + JSONObject query(AlipayIsvParams alipayIsvParams, String orderId); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayOpenSpOperationService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayOpenSpOperationService.java new file mode 100644 index 0000000..9fd7de2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayOpenSpOperationService.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.alipay.AlipaySpOperationInfo; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; + +/* +* 支付宝服务商代运营授权接口 +* +* @author zx +* +* @date 2023/3/8 15:13 +*/ +public interface IAlipayOpenSpOperationService { + + /** 获取支付宝代运营授权二维码 **/ + JSONObject querySpOperationQrcode(AlipayIsvParams alipayIsvParams, String alipayAccount); + + /** 发送支付宝代运营授权消息 **/ + JSONObject applySpOperation(AlipayIsvParams alipayIsvParams, String alipayAccount); + + /** 查询支付宝代运营授权结果 **/ + AlipaySpOperationInfo querySpOperationResult(AlipayIsvParams alipayIsvParams, String alipayAccount); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayShopService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayShopService.java new file mode 100644 index 0000000..e12b92a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/paychannel/alipaybiz/IAlipayShopService.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.interfaces.paychannel.alipaybiz; + +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; + +/* +* 蚂蚁店铺接口 +* +* @author zx +* +* @date 2023/3/14 15:13 +*/ +public interface IAlipayShopService { + + /** 查询店铺详情 **/ + MchStore query(AlipayIsvParams alipayIsvParams, String storeId, String ipRoleId); + + /** 创建店铺 **/ + MchStore create(AlipayIsvParams alipayIsvParams, MchStore mchStore, String ipRoleId); + + /** 修改店铺 **/ + MchStore update(AlipayIsvParams left, MchStore mchStore); + + /** 关闭店铺 **/ + void close(AlipayIsvParams alipayIsvParams, String alipayShopId); + + /** 根据申请单查询店铺创建结果 **/ + MchStore createResultQuery(AlipayIsvParams alipayIsvParams, String orderId); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IAppPushService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IAppPushService.java new file mode 100644 index 0000000..d490650 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IAppPushService.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.core.interfaces.push; + +import com.jeequan.jeepay.core.model.DBAppPushConfig; + +import java.util.Map; +import java.util.Set; + +/** + * app推送服务 + * + * @author zx + * + * @date 2022/1/11 15:23 + */ +public interface IAppPushService { + + /** app推送 */ + Map> pushMessageToList(String content, Set cIds, DBAppPushConfig appPushConfig); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IBaiduBceService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IBaiduBceService.java new file mode 100644 index 0000000..0f19ce6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/push/IBaiduBceService.java @@ -0,0 +1,20 @@ +package com.jeequan.jeepay.core.interfaces.push; + +import com.jeequan.jeepay.core.model.DBBaiduBceConfig; + +/** + * 百度语音 + * + * @author zx + * + * @date 2022/1/11 15:23 + */ +public interface IBaiduBceService { + + /** 获取token */ + String getBaiduBceToken(DBBaiduBceConfig baiduBceConfig); + + /** 清空本地缓存token */ + void clearBaiduBceTokenCache(DBBaiduBceConfig baiduBceConfig); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferFlowService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferFlowService.java new file mode 100644 index 0000000..0218cc6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferFlowService.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.interfaces.transfer; + +import com.jeequan.jeepay.core.entity.TransferSubject; +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; + +import java.util.List; +import java.util.Map; + +/** + * 转账功能抽象 + * + * @author deng + * @since 2024/4/25 + */ +public interface IChannelTransferFlowService { + + /** + * 发起转账 + * @param transferSubjects 主体列表 + * @param bizData 业务数据,暂定主体ID为key, 金额为value值 + */ + void transfer(List transferSubjects, Map bizData); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferSubjectService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferSubjectService.java new file mode 100644 index 0000000..630d3a8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/transfer/IChannelTransferSubjectService.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.interfaces.transfer; + +import com.jeequan.jeepay.core.model.tranfer.TransferBasicInfo; +import org.apache.commons.lang3.tuple.MutablePair; + +import javax.servlet.http.HttpServletRequest; + +/** + * 转账发起方和接收方对象相关的操作 + * + * @author deng + * @since 2024/4/25 + */ +public interface IChannelTransferSubjectService { + + MutablePair parseParam(HttpServletRequest request, String customApplyId); + + /** + * 添加转账方 + * @param transferBasicInfo + */ + void addExporter(TransferBasicInfo transferBasicInfo); + + /** + * 添加接收方 + * @param transferBasicInfo + */ + void addAcceptor(TransferBasicInfo transferBasicInfo); + + /** + * 添加转账方或接收方的三方请求业务回调 + */ + default Object callback(Object bizContent) { + callbackProcess(bizContent); + return retOk(bizContent); + } + + void callbackProcess(Object bizContent); + + Object retOk(Object bizContent); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxLiteUrlLinkService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxLiteUrlLinkService.java new file mode 100644 index 0000000..eb81547 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxLiteUrlLinkService.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.core.interfaces.wxmp; + +import com.jeequan.jeepay.core.model.context.MchAppConfigContext; + +/* +* 接口:获取小程序 URL Link +* +* @author zx +* +* @date 2021/5/8 15:14 +*/ +public interface IWxLiteUrlLinkService { + + /** + * 获取小程序 URL Link接口 + * 接口文档: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html + * + * @param mchAppConfigContext + * @param query + * @param millisecond + * @return link地址 + */ + String generateUrlLink(MchAppConfigContext mchAppConfigContext, String query, long millisecond); + + + /** + * 获取小程序 URL SCHEME接口 + * 接口文档: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateScheme.html + * @param mchAppConfigContext + * @param query + * @param millisecond + * @return link地址 + */ + String generateSchemeLink(MchAppConfigContext mchAppConfigContext, String query, long millisecond); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxMpTemplateMsgService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxMpTemplateMsgService.java new file mode 100644 index 0000000..c3d20b1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/interfaces/wxmp/IWxMpTemplateMsgService.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.interfaces.wxmp; + +import com.jeequan.jeepay.core.entity.MchWxmpUser; +import com.jeequan.jeepay.core.model.DBWxMpConfig; +import com.jeequan.jeepay.core.model.wx.wxmp.WxUserInfo; + +import java.util.List; + +/* +* 接口:微信公众号授权回调 code -> openid +* +* @author zx +* +* @date 2021/5/8 15:14 +*/ +public interface IWxMpTemplateMsgService { + + /** + * 回调code 获取accessToken 获取wxUserInfo + * @param code + * @return + */ + WxUserInfo code2WxUserInfo(String code, DBWxMpConfig wxMpConfig); + + /** + * 发送模板消息 + * @param userList + * @param templateMessage + */ + void sendTemplateMessage(List userList, String templateMessage, DBWxMpConfig wxMpConfig,String templateId); + +// +// /** +// * 扩展发送消息 +// * @param userList +// * @param templateMessage +// */ +// void sendTemplateMessageExtend(List userList, String templateMessage, DBWxMpConfig wxMpConfig); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTPayload.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTPayload.java new file mode 100644 index 0000000..d7395b3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTPayload.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.core.jwt; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.security.JeeUserDetails; +import com.jeequan.jeepay.core.utils.DateKit; +import lombok.Data; + +import java.util.Map; + +/* +* JWT payload 载体 +* 格式: + { + "sysUserId": "10001", + "created": "1568250147846", + "cacheKey": "KEYKEYKEYKEY", + } +* @author terrfly +* @date 2021/6/8 18:01 +*/ +@Data +public class JWTPayload { + + // 登录页面(终端)类型 + // WEB - 浏览器页面登录, APP- APP登录, LITE-小程序, FACEAPP-刷脸设备 + public interface LOGIN_PAGE_TYPE { + String WEB = "WEB"; + String APP = "APP"; + String LITE = "LITE"; + String FACE_APP = "FACEAPP"; + } + + /** 认证类型: 区分哪种方式登录的 **/ + public interface CREDENTIAL_AUTH_TYPE{ + String PASSWD = "PWD"; // 密码认证方式 直接写password被检测为高危漏洞(密码硬编码)。。 + String TEL_CODE = "TELCODE"; // 手机验证码认证 + String QR_CODE = "QRCODE"; // 扫码认证 + } + + private Long sysUserId; //登录用户ID + private Long created; //创建时间, 格式:13位时间戳 + private String cacheKey; //redis保存的key + private String loginType; // 登录页面(终端)类型 + + protected JWTPayload(){} + + public JWTPayload(JeeUserDetails jeeUserDetails){ + + this.setSysUserId(jeeUserDetails.getSysUser().getSysUserId()); + this.setCreated(DateKit.currentTimeMillis()); + this.setCacheKey(jeeUserDetails.getCacheKey()); + this.setLoginType(jeeUserDetails.getLoginType()); + + } + + + /** toMap **/ + public Map toMap(){ + JSONObject json = (JSONObject)JSONObject.toJSON(this); + return json.toJavaObject(Map.class); + } + + // 判断是否app登录 + public boolean isAppLogin(){ + return LOGIN_PAGE_TYPE.APP.equals(getLoginType()) || LOGIN_PAGE_TYPE.LITE.equals(getLoginType()) || LOGIN_PAGE_TYPE.FACE_APP.equals(getLoginType()); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTUtils.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTUtils.java new file mode 100644 index 0000000..1d0da99 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/jwt/JWTUtils.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.core.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +/* +* JWT工具包 +* +* @author terrfly +* @date 2021/6/8 16:32 +*/ +public class JWTUtils { + + /** 生成token **/ + public static String generateToken(JWTPayload jwtPayload, String jwtSecret) { + return Jwts.builder() + .setClaims(jwtPayload.toMap()) + //过期时间 = 当前时间 + (设置过期时间[单位 :s ] ) token放置redis 过期时间无意义 + //.setExpiration(new Date(DateKit.currentTimeMillis() + (jwtExpiration * 1000) )) + .signWith(SignatureAlgorithm.HS512, jwtSecret) + .compact(); + } + + /** 根据token与秘钥 解析token并转换为 JWTPayload **/ + public static JWTPayload parseToken(String token, String secret){ + try { + Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + + JWTPayload result = new JWTPayload(); + result.setSysUserId(claims.get("sysUserId", Long.class)); + result.setCreated(claims.get("created", Long.class)); + result.setCacheKey(claims.get("cacheKey", String.class)); + result.setLoginType(claims.get("loginType", String.class)); + + return result; + + + } catch (Exception e) { + return null; //解析失败 + } + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ApiRes.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ApiRes.java new file mode 100644 index 0000000..dabe352 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ApiRes.java @@ -0,0 +1,133 @@ +package com.jeequan.jeepay.core.model; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.jeequan.jeepay.core.constants.ApiCodeEnum; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +/** + * 接口返回对象 + * + * @author terrfly + * @date 2021/6/8 16:35 + */ +@Data +@AllArgsConstructor +public class ApiRes { + + /** + * 业务响应码 + **/ + private Integer code; + + /** + * 业务响应信息 + **/ + private String msg; + + /** + * 数据对象 + **/ + private Object data; + + /** + * 数据对象 (加密格式) + **/ + private String encryptData; + + /** + * 签名值 + **/ + private String sign; + + /** + * 输出json格式字符串 + **/ + public String toJSONString() { + return JSON.toJSONString(this); + } + + /** + * 业务处理成功 + **/ + public static ApiRes ok() { + return ok(null); + } + + /** + * 业务处理成功 + **/ + public static ApiRes ok(Object data) { + return new ApiRes(ApiCodeEnum.SUCCESS.getCode(), ApiCodeEnum.SUCCESS.getMsg(), data, null, null); + } + + /** + * 业务处理成功, 返回简单json格式 + **/ + public static ApiRes ok4newJson(String key, Object val) { + return ok(JsonKit.newJson(key, val)); + } + + /** + * 业务处理成功, 封装分页数据, 仅返回必要参数 + **/ + public static ApiRes page(IPage iPage) { + return page(iPage, null); + } + + /** + * 业务处理成功, 封装分页数据, 仅返回必要参数 带扩展参数 + **/ + public static ApiRes page(IPage iPage, JSONObject extParams) { + + JSONObject result = new JSONObject(); + result.put("records", iPage.getRecords()); //记录明细 + result.put("total", iPage.getTotal()); //总条数 + result.put("current", iPage.getCurrent()); //当前页码 + result.put("hasNext", iPage.getPages() > iPage.getCurrent()); //是否有下一页 + + if (extParams != null) { + result.putAll(extParams); // 额外响应参数 + } + return ok(result); + } + + /** + * 业务处理成功, 封装分页数据, 仅返回必要参数 + **/ + public static ApiRes page(IPage iPage, List list, long count) { + + iPage.setTotal(count); + + JSONObject result = new JSONObject(); + result.put("records", list); //记录明细 + result.put("total", count); //总条数 + result.put("current", iPage.getCurrent()); //当前页码 + result.put("hasNext", iPage.getPages() > iPage.getCurrent()); //是否有下一页 + return ok(result); + } + + /** + * 业务处理失败 + **/ + public static ApiRes fail(ApiCodeEnum apiCodeEnum, String... params) { + + if (params == null || params.length <= 0) { + return new ApiRes(apiCodeEnum.getCode(), apiCodeEnum.getMsg(), null, null, null); + } + return new ApiRes(apiCodeEnum.getCode(), String.format(apiCodeEnum.getMsg(), params), null, null, null); + } + + /** + * 自定义错误信息, 原封不用的返回输入的错误信息 + **/ + public static ApiRes customFail(String customMsg) { + return new ApiRes(ApiCodeEnum.CUSTOM_FAIL.getCode(), customMsg, null, null, null); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/AppletResult.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/AppletResult.java new file mode 100644 index 0000000..80f9b9c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/AppletResult.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model; + +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.Data; + +/** + * TODO + * 小程序支付参数 + * @author crystal + * @date 2023/11/29 11:13 + */ +@Data +public class AppletResult { + + private String appid; + + private String ghid; + + private String path; + + private String env; + + private String ext; + + private String scheme; + + private String payUrl; + + private Byte status; + + public AppletResult(WxpayOauth2Params wxpayOauth2Params,String scheme,String query) { + this.appid = wxpayOauth2Params.getLiteAppId(); + this.ghid = wxpayOauth2Params.getLiteGhid(); + this.path = wxpayOauth2Params.getLitePagePath() + "?"+ query; + this.env = wxpayOauth2Params.getLiteEnv(); + this.scheme = scheme; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/BaseModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/BaseModel.java new file mode 100644 index 0000000..30f2c4c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/BaseModel.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.core.model; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; +import com.jeequan.jeepay.core.utils.DateKit; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +import java.io.Serializable; +import java.util.Date; + +/* +* BaseModel 封装公共处理函数 +* +* @author terrfly +* @date 2021/6/8 16:49 +*/ +@Data +@SuperBuilder(toBuilder = true) +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class BaseModel implements Serializable{ + + private static final long serialVersionUID = 1L; + + /** ext参数, 用作扩展参数, 会在转换为api数据时自动将ext全部属性放置在对象的主属性上, 并且不包含ext属性 **/ + + //获取的时候设置默认值 + /** api接口扩展字段, 当包含该字段时 将自动填充到实体对象属性中如{id:1, ext:{abc:222}} 则自动转换为: {id:1, abc:222}, + * 需配合ResponseBodyAdvice使用 + * **/ + @TableField(exist = false) + private JSONObject ext; + + @TableField(exist = false) + private Date[] dateRange; + + + //设置扩展字段 + public BaseModel addExt(String key, Object val) { + + if(ext == null) { + ext = new JSONObject(); + } + ext.put(key,val); + return this; + } + + /** get ext value 可直接使用JSONObject对象的函数 **/ + public JSONObject extv() { + return ext == null ? new JSONObject() : ext; + } + + + /** + * 获取查询的时间范围 + * @return + */ + public Date[] buildQueryDateRange(){ + Date[] queryDateRanges = DateKit.getQueryDateRange(extv().getString("queryDateRange")); + this.dateRange = queryDateRanges; + return queryDateRanges; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/Capability.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/Capability.java new file mode 100644 index 0000000..d4ceea2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/Capability.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model; + + +import lombok.Data; +import lombok.ToString; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * 代码功能枚举 + */ +@Data +@ToString +public class Capability implements Serializable { + + /*[ + {"key": "PAY_BASE", "value": "Y", "desc": "当面付"}, + {"key": "H5_PAY", "value": "Y", "desc": "H5支付"}, + {"key": "TURNS_PAY", "value": "Y", "desc": "轮询码开关"}, + ]*/ + public static final Capability PAY_BASE = new Capability("PAY_BASE", "Y", "当面付"); + public static final Capability H5_PAY = new Capability("H5_PAY", "Y", "H5支付"); + public static final Capability TURNS_PAY = new Capability("TURNS_PAY", "Y", "轮询码开关"); + + public static final Map MAP = new HashMap<>(); + + static { + MAP.put(PAY_BASE.key, PAY_BASE); + MAP.put(H5_PAY.key, H5_PAY); + MAP.put(TURNS_PAY.key, TURNS_PAY); + } + + private final String key; + private final String value; + private final String desc; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/CashierConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/CashierConfig.java new file mode 100644 index 0000000..9b043ab --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/CashierConfig.java @@ -0,0 +1,126 @@ +package com.jeequan.jeepay.core.model; + +import cn.hutool.core.collection.CollUtil; +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/*** + * 收银台配置 + * + * @author terrfly + * @date 2023/3/20 13:40 + */ +@Data +public class CashierConfig { + + /** + * 便捷收银台LOGO及底部显示配置 + **/ + public static final String SELF_CASHIER_SITEINFO_TYPE_DEFAULT = "DEFAULT"; // 默认 + public static final String SELF_CASHIER_SITEINFO_TYPE_NONE = "NONE"; // 为空 + public static final String SELF_CASHIER_SITEINFO_TYPE_CUSTOM = "CUSTOM"; // 自定义 + + + /** + * 状态 + **/ + private Byte state; + + /** + * logo显示类型 + **/ + private String siteInfoType; + + /** + * 微信H5支持的支付方式,并排序 + **/ + private List wxH5PaywayList; + + /** + * 支付宝wap 支持的支付方式,并排序 + **/ + private List aliwapPaywayList; + + + /** + * 处理查询到的全部产品: allWaycode 商户所有开通的支付产品 + **/ + public void processWacodesWithWxH5AndALiwap(Set allWaycode) { + + // 包含任意一个配置项目 则支持wxH5 支付产品, 否则将关闭。 + if (!CollUtil.intersectionDistinct(allWaycode, this.getWxH5PaywayList()).isEmpty()) { + + allWaycode.add(CS.PAY_WAY_CODE.WX_H5); + + } else { + + allWaycode.remove(CS.PAY_WAY_CODE.WX_H5); + + } + + + // 包含任意一个配置项目 则支持 aliWay 支付产品, 否则将关闭。 + if (!CollUtil.intersectionDistinct(allWaycode, this.getAliwapPaywayList()).isEmpty()) { + + allWaycode.add(CS.PAY_WAY_CODE.ALI_WAP); + + } else { + + allWaycode.remove(CS.PAY_WAY_CODE.ALI_WAP); + + } + + } + + + /** + * 获取到 商户可用的产品列表: 根据: wxH5PaywayList 排序 + **/ + public List getWxH5PaywayListWithIntersectionDistinct(Set allWaycode) { + + if (allWaycode == null || allWaycode.isEmpty()) { + return new ArrayList<>(); + } + + if (this.wxH5PaywayList == null || this.wxH5PaywayList.isEmpty()) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + for (String s : this.wxH5PaywayList) { + if (allWaycode.contains(s)) { + result.add(s); + } + } + + return result; + } + + /** + * 获取到 商户可用的产品列表: 根据: aliwapPaywayList 排序 + **/ + public List getAliWapPaywayListWithIntersectionDistinct(Set allWaycode) { + + if (allWaycode == null || allWaycode.isEmpty()) { + return new ArrayList<>(); + } + + if (this.aliwapPaywayList == null || this.aliwapPaywayList.isEmpty()) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + for (String s : this.aliwapPaywayList) { + if (allWaycode.contains(s)) { + result.add(s); + } + } + + return result; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApiMapConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApiMapConfig.java new file mode 100644 index 0000000..3516de5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApiMapConfig.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 高德地图配置参数 + * + * @author xiaoyu + * @date 2022/2/21 10:05 + */ +@Data +public class DBApiMapConfig implements Serializable { + + /** 高德地图商户web端key **/ + private String apiMapWebKey; + + /** 高德地图商户web端secret **/ + private String apiMapWebSecret; + + /** 高德地图商户端web服务key **/ + private String apiMapWebServiceKey; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBAppPushConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBAppPushConfig.java new file mode 100644 index 0000000..796f869 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBAppPushConfig.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信公众号提醒配置 + **/ +@Data +public class DBAppPushConfig implements Serializable { + + public final static String GT_APP_PUSH = "https://restapi.getui.cn"; + + /** uniPush版本,1-1.0 2-2.0 **/ + private Byte uniPushVersion; + + /** AppID **/ + private String uniPushAppId; + + /** AppKey **/ + private String uniPushAppKey; + + /** MasterSecret **/ + private String uniPushMasterSecret; + + /** uniPush2.0 uniPush云函数URL **/ + private String uniPushCloudUrl; + + /** uniPush2.0 uniPush查询失效cid云函数URL **/ + private String uniPushQueryInvalidatedCidsUrl; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApplicationConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApplicationConfig.java new file mode 100644 index 0000000..1a6bf5a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBApplicationConfig.java @@ -0,0 +1,89 @@ +package com.jeequan.jeepay.core.model; + +import cn.hutool.core.util.URLUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.service.ISysConfigService; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.SpringBeansUtil; +import lombok.Data; + +import java.io.Serializable; + +/* +* 系统应用配置项定义Bean +* +* @author terrfly +* @date 2021/6/8 16:35 +*/ +@Data +public class DBApplicationConfig implements Serializable { + + /** 运营系统地址 **/ + private String mgrSiteUrl; + + /** 商户系统地址 **/ + private String mchSiteUrl; + + /** 支付网关地址 **/ + private String paySiteUrl; + + /** 服务商系统地址 **/ + private String agentSiteUrl; + + /** 会员系统地址 **/ + private String memberSiteUrl; + + /** 静态文件CDN域名 **/ + private String staticCdnHost; + + /** 生成 【收银台页面跳转地址】 **/ + public String genCashierPayUrl(String appId, String storeId){ + return getPaySiteUrl() + "/api/cashierPage" + "/" + JeepayKit.aesEncode(appId) + "/" + JeepayKit.aesEncode(storeId); + } + + /** 生成 【web统一收银台跳转地址】 **/ + public String genWebCashierPayUrl(String payOrderId){ + return getPaySiteUrl() + "/api/webCashier" + "/" + JeepayKit.aesEncode(payOrderId); + } + + /** 生成 【jsapi统一收银台跳转地址】 **/ + public String genUniJsapiPayUrl(Byte type, String entry, String id, String isvNo,Long amt){ + return getPaySiteUrl() + "/pages/hub/" + entry+ "/"+isvNo+"/?"+JeepayKit.TOKEN_KEY+"=" + genQrToken(type, id,amt); + } + + /** 生成 【jsapi统一收银台跳转地址】 **/ + public String genUniJsapiPayUrl(Byte type, String entry, String id, String isvNo){ + return getPaySiteUrl() + "/pages/hub/" + entry+ "/"+isvNo+"/?"+JeepayKit.TOKEN_KEY+"=" + genQrToken(type, id,null); + } + + /** 生成 【jsapi统一收银台】oauth2获取用户ID回调地址 **/ + public String genOauth2RedirectUrlEncode(String token){ + return URLUtil.encodeAll(getPaySiteUrl() + "/cashier/pages/oauth2/callback?"+JeepayKit.TOKEN_KEY+"=" + token); + } + + /** 生成 【商户获取渠道用户ID接口】oauth2获取用户ID回调地址 **/ + public String genMchChannelUserIdApiOauth2RedirectUrlEncode(JSONObject param){ + return URLUtil.encodeAll(getPaySiteUrl() + "/api/channelUserId/oauth2Callback/" + JeepayKit.aesEncode(param.toJSONString())); + } + + /** 生成 【jsapi统一收银台二维码图片地址】 **/ + public String genScanImgUrl(String url){ + return getPaySiteUrl() + "/api/scan/imgs/" + JeepayKit.aesEncode(url) + ".png"; + } + + /** 生成 【支付宝 isv子商户的授权链接地址】 **/ + public String genAlipayIsvsubMchAuthUrl(String isvNo, String mchAppId){ + return getPaySiteUrl() + "/api/channelbiz/alipay/redirectAppToAppAuth/" + isvNo + "_" + mchAppId; + } + + /** 生成 收银台的TOKEN **/ + public String genQrToken(Byte type, String id,Long amt){ +// if(amt == null){ +// return JeepayKit.aesEncode(String.format("{type: %s, id: '%s' }", type, id)); +// }else{ +// return JeepayKit.aesEncode(String.format("{type: %s, id: '%s',amt: %s}", type, id , amt)); +// } + ISysConfigService sysService = SpringBeansUtil.getBean("sysConfigService", ISysConfigService.class); + return sysService.genQrToken(type,id,amt); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBBaiduBceConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBBaiduBceConfig.java new file mode 100644 index 0000000..955b5c8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBBaiduBceConfig.java @@ -0,0 +1,21 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信公众号提醒配置 + **/ +@Data +public class DBBaiduBceConfig implements Serializable { + + public final static String BAIDU_OAUTH_URL = "https://aip.baidubce.com/oauth/2.0/token?"; + + /** baiduBceAppKey **/ + private String baiduBceAppKey; + + /** baiduBceAppSecret **/ + private String baiduBceAppSecret; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBDefaultConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBDefaultConfig.java new file mode 100644 index 0000000..56627fa --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBDefaultConfig.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.core.model; + +import com.jeequan.jeepay.core.model.applyment.CashoutFee; +import lombok.Data; + +/** +* DB的默认配置 +* +* @author terrfly +* @date 2022/5/16 17:05 +*/ +@Data +public class DBDefaultConfig { + + /** 默认渠道商号 */ + private String defaultIsvNo; + + /** 默认服务商号 */ + private String defaultAgentNo; + + /** + * 自营商户号 + */ + private String platformSelfMchNo; + + /** 商户注册是否必填邀请码 */ + private Byte mchRegisterInviteCodeRequired; + + /** 商户注册是否开启便捷收银台 */ + private Byte mchRegisterSelfCashierState; + + /** 商户注册是否开启WEB收银台 */ + private Byte mchRegisterWebCashierState; + + /** 商户注册是否开启会员功能 */ + private Byte mchRegisterMemberState; + + /** 商户会员最大储值余额 */ + private Long mchMbrMaxBalance; + + /** 商户注册默认级别 */ + private String mchRegisterLevel; + + /** 微信小程序审核帐号 */ + private String wxAuditUser; + + /** 提现手续费配置 */ + private CashoutFee castOutFeeRule; + + /** 默认登录密码 */ + private String defaultPassword; + + /** 是否开启商户进件预审功能 */ + private Byte mchApplymentPreAudit; + /** 商户自主进件时间限制 */ + private String mchApplyTimeLimit; + + /** 是否开启服务商进件预审功能 */ + private Byte agentApplymentPreAudit; + /** 服务商发起进件默认时间限制 */ + private String agentApplyTimeLimit; + + /** 服务商注册时是否审核 */ + private Byte agentRegisterIsAudit; + + /** 服务商新增下级代理时是否审核 */ + private String agentNewSubIsAudit; + + /** 服务商注册是否必填邀请码 */ + private Byte agentRegisterInviteCodeRequired; + + /** 服务商是否支持划拨码牌、设备 */ + private Byte isSupportAgentAllot; + + /** 进件图片上传大小 M **/ + private String applymentImgUploadSize; + + /** + * 系统收款商户号 + */ + private String sysPaymentMchNo; +} + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBEmailConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBEmailConfig.java new file mode 100644 index 0000000..b422604 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBEmailConfig.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/** + * TODO + * + * @author crystal + * @date 2023/12/20 14:43 + */ +@Data +public class DBEmailConfig { + + private String emailAccountNo; + + private String emailHost; + + private String emailName; + + private String emailPassword; + + private Integer emailPort; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBMarketingConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBMarketingConfig.java new file mode 100644 index 0000000..a295962 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBMarketingConfig.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/** + * TODO + * + * @author crystal + * @date 2023/12/20 14:43 + */ +@Data +public class DBMarketingConfig { + + /** + * 营销配置参数 广告名称 + */ + private String adsName; + + /** + * 营销配置参数 广告权限 + */ + private String adsStatus; + + + /** + * 营销配置参数 广告链接 + */ + private String adsUrl; + + /** + * 营销配置参数 营销红包 + */ + private String platRedPacket; + + /** + * 营销配置参数 领取红包页面背景图1 + */ + private String sysBgUrl; + + /** + * 营销配置参数 领取红包页面内容图2 + */ + private String sysBgUrl2; + + /** + * 系统分账的商户号 + */ + private String mchNo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOCRConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOCRConfig.java new file mode 100644 index 0000000..1a83de0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOCRConfig.java @@ -0,0 +1,53 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * + * OCR配置参数 + * @author xiaoyu + * @date 2022/1/11 9:54 + */ +@Data +public class DBOCRConfig implements Serializable { + + // 阿里云 + public static String OCR_ALI = "ali"; + // 腾讯云 + public static String OCR_TENCENT = "tencent"; + + // 百度 + public static String OCR_BAIDU = "baidu"; + + // OCR识别使用类型 1-腾讯OCR 2-阿里OCR 3-百度OCR + public static byte OCR_TYPE_TENCENT = 1; + public static byte OCR_TYPE_ALI = 2; + public static byte OCR_TYPE_BAIDU = 3; + + // 调用接口类型 + public static String OCR_TYPE_ID_CARD = "idCard"; + public static String OCR_TYPE_BANK_CARD = "bankCard"; + public static String OCR_TYPE_LICENSE = "license"; + + /** OCR识别使用状态 0-关闭 1-开启 **/ + private byte ocrState; + + /** OCR识别使用类型 1-腾讯OCR 2-阿里OCR **/ + private byte ocrType; + + /** 腾讯OCR参数 **/ + private String tencentSecretId; + private String tencentSecretKey; + + /** 阿里OCR参数 **/ + private String aliAccessKeyId; + private String aliAccessKeySecret; + + + /** 百度云 OCR **/ + private String baiduApiKey; + private String baiduSecretKey; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOEMConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOEMConfig.java new file mode 100644 index 0000000..3124673 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOEMConfig.java @@ -0,0 +1,219 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/*** + * 系统 OEM网站配置信息 + * + * @author terrfly + * @date 2022/2/15 10:12 + */ +@Data +public class DBOEMConfig { + + /** + * 全局配置: 网站icon-url + */ + private String iconUrl; + + /** + * 全局配置: 系统logo url + */ + private String sysLogoUrl; + + /** + * 全局配置: 系统缩小版logo url + */ + private String sysMinLogoUrl; + + /** + * 全局配置: 系统logo url + */ + private String darkSysLogoUrl; + + /** + * 全局配置: 系统缩小版logo url + */ + private String darkSysMinLogoUrl; + + /** + * 全局配置: 授权函文件 url + */ + private String promiseFile; + + /** + * 全局配置:系统名称 + */ + private String sysName; + + /** + * 全局配置: 公司全称 + */ + private String companyName; + + /** + * 全局配置:公司电话 + */ + private String companyTel; + + /** + * 全局配置:公司客服电话 + */ + private String companyServiceTel; + + /** + * 全局配置:公司email + */ + private String companyEmail; + + /** + * 全局配置: 公司位置信息 + */ + private String companyAddress; + + /** + * 备案和版权信息:工信部ICP备案 + */ + private BizReportOEMConfig reportIcp; + + /** + * 备案和版权信息:公网安备案 + */ + private BizReportOEMConfig reportGa; + + /** + * 备案和版权信息:中国支付清算协会备案 + */ + private BizReportOEMConfig reportJh; + + /** + * 备案和版权信息:电信增值业务许可 + */ + private BizReportOEMConfig reportDx; + + /** + * 备案和版权信息:版权 + */ + private BizReportOEMConfig copyrightInfo; + + /** + * 商户通配置: APP顶部图 + */ + private String appTopImgUrl; + + /** + * 商户通配置: 小程序二维码 + */ + private String appletImgUrl; + + /** + * 展业宝配置: APP顶部图 + */ + private String agentAppTopImgUrl; + + /** + * 展业宝配置: 小程序二维码 + */ + private String agentAppletImgUrl; + + /** + * 商户通配置: 小程序分享图 + */ + private String shareImgUrl; + + /** + * 展业宝配置: 小程序分享图 + */ + private String agentShareImgUrl; + + /** + * 运营平台 配置信息 + */ + private BizSysOEMConfig mgr; + + /** + * 商户系统 配置信息 + */ + private BizSysOEMConfig mch; + + /** + * 服务商系统 配置信息 + */ + private BizSysOEMConfig agent; + + + /** + * 业务系统的配置对象 + **/ + @Data + public static class BizSysOEMConfig { + + /** + * 配置: 系统logo url + */ + private String sysLogoUrl; + + /** + * 配置: 系统缩小版logo url + */ + private String sysMinLogoUrl; + + /** + * 配置: 系统logo url + */ + private String darkSysLogoUrl; + + /** + * 配置: 系统缩小版logo url + */ + private String darkSysMinLogoUrl; + + /** + * 主题色 + **/ + private String sysPrimaryColor; + + /** + * 登录页背景图 + **/ + private String loginPageBGImgUrl; + + /** + * 登录卡片位置 left, center, right + **/ + private String loginPageCardPosition; + + /** + * 登录页背景类型 0-背景图 1-轮播图 + **/ + private Byte loginBgType; + + /** + * 轮播图背景配置ID + **/ + private Long loginBgId; + + /** + * 登录页banner配置 + **/ + private String bannerConfig; + } + + /** + * 备案和版权的配置对象 + **/ + @Data + public static class BizReportOEMConfig { + /** + * 配置: 文字描述 + */ + private String configDesc; + + /** + * 配置: 链接地址 + */ + private String configUrl; + } + +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOSSConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOSSConfig.java new file mode 100644 index 0000000..b5659db --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBOSSConfig.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.core.model; + +import com.alibaba.fastjson.JSON; +import lombok.Data; + +@Data +public class DBOSSConfig { + + private String ossUseType; + private String aliyunOssConfig; + /** oss公共读文件地址 **/ + private String ossPublicSiteUrl; + + private AliyunOssConfigModel aliyunOssConfigModel; + + public AliyunOssConfigModel getAliyunOssConfigModel(){ + if(aliyunOssConfigModel != null){ + return aliyunOssConfigModel; + } + + AliyunOssConfigModel parseObject = JSON.parseObject(this.aliyunOssConfig, AliyunOssConfigModel.class); + this.aliyunOssConfigModel = parseObject; + return parseObject; + } + + @Data + public static class AliyunOssConfigModel{ + private String endpoint; + private String publicBucketName; + private String privateBucketName; + private String accessKeyId; + private String accessKeySecret; + private Long expireTime; + } + +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBPaymentConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBPaymentConfig.java new file mode 100644 index 0000000..a94775f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBPaymentConfig.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/** + * TODO + * 打款配置 + * @author crystal + * @date 2024/3/25 18:05 + */ +@Data +public class DBPaymentConfig { + + /** + * appid + */ + private String appId; + + /** 密钥 **/ + private String secret; + + private String taskNo; + + private String paymentType; + /** + * 域名 + */ + private String domain; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBTreatyConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBTreatyConfig.java new file mode 100644 index 0000000..54b58fa --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBTreatyConfig.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/** + * 系统 隐私政策与服务协议配置 + * + * @author xiaoyu + * @date 2022/2/16 14:40 + */ +@Data +public class DBTreatyConfig { + + /** 隐私政策 */ + private String privacyPolicy; + + /** 服务协议 */ + private String serviceAgreement; + + /** 隐私政策 */ + private String agentPrivacyPolicy; + + /** 服务协议 */ + private String agentServiceAgreement; + + /** 隐私政策 */ + private String storePrivacyPolicy; + + /** 服务协议 */ + private String storeServiceAgreement; + + /** 产品服务 */ + private String servicePaymentFlund; +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBWxMpConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBWxMpConfig.java new file mode 100644 index 0000000..30dff9a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBWxMpConfig.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 微信公众号提醒配置 + **/ +@Data +public class DBWxMpConfig implements Serializable { + + public final static String DEFAULT_WX_AUTH_DOMAIN = "https://open.weixin.qq.com/connect/oauth2/authorize"; + + public static String mchAuthUrl = "{{mchAuthRedirectUrl}}?appid={{appId}}&scope=snsapi_userinfo&state=&redirect_uri={{paySiteUrl}}/api/wxmpCallback/msg/wxAuthRedirect/{{mchNo}}/{{sysUserId}}&response_type=code#wechat_redirect"; + + /** 微信公众号AppId **/ + private String wxAppId; + + /** 微信公众号AppSecret **/ + private String wxAppSecret; + + /** 微信公众号二维码 **/ + private String wxmpUrl; + + /** 微信校验文件名 **/ + private String wxCheckFileName; + + /** 微信校验文件内容 **/ + private String wxCheckFileValue; + + /** 商户授权回调地址(微信公众号端服务器配置) **/ + private String mchAuthRedirectUrl; + + /** 模板消息ID **/ + private String paySuccMsgTemplateId; + + /** 模板消息内容备注 **/ + private String paySuccMsgTemplateContentRemark; + + /** 通知消息模板ID **/ + private String noticeMsgTemplateId; + + public String getPaySuccMsgTemplateContent() { + // return "[{\"name\":\"first\",\"value\":\"收到新订单\"},{\"name\":\"keyword1\",\"value\":\"{{orderAmount}}\"},{\"name\":\"keyword2\",\"value\":\"{{payProductName}}\"},{\"name\":\"keyword3\",\"value\":\"{{paySuccTime}}\"},{\"name\":\"keyword4\",\"value\":\"{{payOrderId}}\"},{\"name\":\"remark\",\"value\":\"{{remark}}\"}]"; + return "[{\"name\":\"first\",\"value\":\"订单支付成功通知\"},{\"name\":\"amount3\",\"value\":\"{{orderAmount}}\"},{\"name\":\"thing6\",\"value\":\"{{payProductName}}\"},{\"name\":\"time4\",\"value\":\"{{paySuccTime}}\"},{\"name\":\"character_string2\",\"value\":\"{{payOrderId}}\"},{\"name\":\"thing5\",\"value\":\"{{mercName}}\"}]"; + } + + /** + * 获取通知模板 + * @return + */ + public String getNoticeMsgTemplateContent() { + // return "[{\"name\":\"first\",\"value\":\"收到新订单\"},{\"name\":\"keyword1\",\"value\":\"{{orderAmount}}\"},{\"name\":\"keyword2\",\"value\":\"{{payProductName}}\"},{\"name\":\"keyword3\",\"value\":\"{{paySuccTime}}\"},{\"name\":\"keyword4\",\"value\":\"{{payOrderId}}\"},{\"name\":\"remark\",\"value\":\"{{remark}}\"}]"; + return "[{\"name\":\"first\",\"value\":\"门店预警通知\"},{\"name\":\"thing1\",\"value\":\"{{thing1}}\"},{\"name\":\"thing4\",\"value\":\"{{thing4}}\"},{\"name\":\"thing2\",\"value\":\"{{thing2}}\"},{\"name\":\"thing5\",\"value\":\"{{thing5}}\"},{\"name\":\"time6\",\"value\":\"{{time6}}\"}]"; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBsecurityConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBsecurityConfig.java new file mode 100644 index 0000000..2610f1d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/DBsecurityConfig.java @@ -0,0 +1,97 @@ +package com.jeequan.jeepay.core.model; + +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; + +/** + * DB的安全设置 + * + * @author terrfly + * @date 2022/5/16 17:05 + */ +@Data +public class DBsecurityConfig { + + /** + * HTTP传输应用层加密开关 + */ + private Byte httpMessageEncryptFlag; + + /** + * 限制登录次数(xx分钟最多尝试xx次)(0表示不限制) + */ + private LoginErrorLimit loginErrorMaxLimit; + + /** + * 密码规则 + */ + private PasswordRegexp passwordRegexp; + + /** + * 密码有效期(天数) + */ + private Integer passwordExpireDay; + + /** + * 密码有效期超期是否强制更改 + */ + private Byte passwordExpiredMustModify; + + /** + * 平台通信秘钥 + */ + private String platformApiSecret; + + + @Data + public static class LoginErrorLimit { + + /** + * 限制x分钟 + */ + private Long limitMinute; + + /** + * 最大尝试次数 + */ + private Long errMax; + + } + + @Data + public static class PasswordRegexp { + + /** + * 正则表达式 + */ + private String regexpRules; + + /** + * 错误提示 + */ + private String errTips; + + } + + public boolean httpMsgIsEncrypt() { + + if (httpMessageEncryptFlag != null && httpMessageEncryptFlag == CS.YES) { + return true; + } + + return false; + } + + public boolean passwordExpiredIsMustModify() { + + if (passwordExpiredMustModify != null && passwordExpiredMustModify == CS.YES) { + return true; + } + + return false; + } + +} + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/EntMatchRuleModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/EntMatchRuleModel.java new file mode 100644 index 0000000..9ddcdf1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/EntMatchRuleModel.java @@ -0,0 +1,142 @@ +package com.jeequan.jeepay.core.model; + +import com.alibaba.fastjson.JSON; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +/*** + * 权限匹配规则model + * + * @author terrfly + * @since 2022/2/15 13:02 + */ +@Data +@NoArgsConstructor +public class EntMatchRuleModel { + + /** + * 商户类型: 例如值: 1 + **/ + private Byte mchType; + + /** + * 匹配商户级别: 示例值: ['M0'] + **/ + private List mchLevelArray; + + private Boolean epUserEnt; + + /** + * 仅商户 & 商户以获取分账权限才可见 + **/ + private Boolean mchDivisionEnt; + + /** + * 仅商户 & 商户分配广告权限才可见 + **/ + private Boolean mchAdvertEnt; + + /** + * 仅商户 & 商户分配收银台权限才可见 + **/ + private Boolean mchSelfCashierEnt; + + /** + * 仅商户 & 商户开启收银台配置才可见 + **/ + private Boolean mchMemberEnt; + + /** + * 用户类型: 示例值: ['USER_TYPE_11_INIT', 'USER_TYPE_12_INIT'] + **/ + private List userEntRules; + + /** + * 转换对象, 基于数据库的基础标志转换为 待比较对象 + **/ + public static EntMatchRuleModel convertByMch(Byte mchType, String mchLevel, boolean mchDivisionEnt, + boolean mchAdvertEnt, boolean mchSelfCashierEnt, boolean mchMemberEnt) { + + EntMatchRuleModel result = new EntMatchRuleModel(); + result.setMchType(mchType); + result.setMchLevelArray(Collections.singletonList(mchLevel)); + result.setMchDivisionEnt(mchDivisionEnt); + result.setMchAdvertEnt(mchAdvertEnt); + result.setMchSelfCashierEnt(mchSelfCashierEnt); + result.setMchMemberEnt(mchMemberEnt); + return result; + } + + + /** + * 比较 + *

+ * currentInfoConfig : 当前商户/角色的配置项 + * this: 当前菜单条目。 + **/ + public boolean match(EntMatchRuleModel currentInfoConfig) { + + // 比较商户类型 + if (this.mchType != null && !this.mchType.equals(currentInfoConfig.getMchType())) { + return false; + } + + // 比较商户级别 + if (this.mchLevelArray != null && !this.mchLevelArray.contains(currentInfoConfig.getMchLevelArray().get(0))) { + return false; + } + + // 规则存在 && 商户配置明确为 false( 不支持 ) -- 分账 + if (this.mchDivisionEnt != null && Boolean.FALSE.equals(currentInfoConfig.getMchDivisionEnt())) { + return false; + } + + // 规则存在 && 商户配置明确为 false( 不支持 ) -- 广告 + if (this.mchAdvertEnt != null && Boolean.FALSE.equals(currentInfoConfig.getMchAdvertEnt())) { + return false; + } + + // 规则存在 && 商户配置明确为 false( 不支持 ) -- 便捷收银台 + if (this.mchSelfCashierEnt != null && !Boolean.TRUE.equals(currentInfoConfig.getMchSelfCashierEnt())) { + return false; + } + + // 规则存在 && 商户配置明确为 false( 不支持 ) -- 商户会员功能 + if (this.mchMemberEnt != null && !Boolean.TRUE.equals(currentInfoConfig.getMchMemberEnt())) { + return false; + } + + // 匹配成功 + return true; + } + + + // 判断是否匹配上 userEntRules + public boolean matchUserEntRules(String dbUserEntRules) { + + // 当前菜单不支持 userEntRules 判断。 + if (this.getUserEntRules() == null || this.getUserEntRules().isEmpty()) { + return false; + } + + // 用户信息不存在, 不包含 + if (StringUtils.isEmpty(dbUserEntRules)) { + return false; + } + + // 判断是否存在 + List list = JSON.parseArray(dbUserEntRules, String.class); + for (String s : list) { + if (getUserEntRules().contains(s)) { + return true; + } + } + return false; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/IsvChannelConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/IsvChannelConfig.java new file mode 100644 index 0000000..dde97f3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/IsvChannelConfig.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +/** + * 服务商渠道配置参数 + * + * @author xiaoyu + * @date 2023/8/4 10:35 + */ +@Data +public class IsvChannelConfig { + + public static final String OPERATIONAL_TYPE_OFFLINE = "01"; + public static final String OPERATIONAL_TYPE_ONLINE = "02"; + + /** 商家类型 01-线下 02-线上 */ + private String operationalType; +} + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/MchExtInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/MchExtInfo.java new file mode 100644 index 0000000..adf2aee --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/MchExtInfo.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class MchExtInfo implements Serializable { + + /** + * 下载链接 + */ + private String url; + + /** + * 类型 + * 1、网站 + * 2、APP + * 3、小程序 + * 4、公众号/服务号 + * 5、其他 + */ + private Integer type; + + private String name; + + private String content; + + /** + * 1、已上线; + * 2、未上线; + */ + private Integer status; + + private String remark; + + private String pic1Url; + + private String pic2Url; + + private String pic3Url; + + private String pic4Url; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OCRImgParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OCRImgParams.java new file mode 100644 index 0000000..6cbc744 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OCRImgParams.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model; + +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import lombok.Data; + +/** + * OCR识别参数 + * + * @author xiaoyu + * @date 2022/1/12 11:06 + */ +@Data +public class OCRImgParams extends ApplymentBasicInfo { + + /** [营业执照]法人姓名 **/ + private String licensePerson; + /** [营业执照]经营范围 **/ + private String licenseBusiness; + /** 法人性别 **/ + private String idcardSex; + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OriginalRes.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OriginalRes.java new file mode 100644 index 0000000..23b7dfe --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/OriginalRes.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/* + * 返回原始数据 + * + * @author terrfly + * @date 2021/6/8 16:37 + */ +@Data +@AllArgsConstructor +public class OriginalRes { + + /** + * 返回数据 + **/ + private Object data; + + public static OriginalRes ok(Object data) { + return new OriginalRes(data); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/PrefixConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/PrefixConfig.java new file mode 100644 index 0000000..245b47b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/PrefixConfig.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class PrefixConfig { + + @Value("${prefix.isv:V}") + private String isv; + + @Value("${prefix.agent:P}") + private String agent; + + @Value("${prefix.mch:U}") + private String mch; + + @Value("${prefix.mch-applyment:B}") + private String mchApplyment; + + @Value("${prefix.mch-notify-no:BG}") + private String mchNotifyNo; + + @Value("${prefix.store:S}") + private String store; + + @Value("${prefix.pay-order:O}") + private String payOrder; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/QRCodeParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/QRCodeParams.java new file mode 100644 index 0000000..670b7ed --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/QRCodeParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class QRCodeParams { + + // 二维码扫码类型: 1 - 统一下单的聚合二维码, 2 - 码牌二维码 3 - 设备二维码 4 - 路由二维码 + public static final byte TYPE_PAY_ORDER = 1; + public static final byte TYPE_QRC = 2; + public static final byte TYPE_QRC_DEVICE = 3; + public static final byte TYPE_ROUTE = 4; + + /** 应用类型: 微信/ 支付宝 **/ + public static final String PAGE_TYPE_WECHAT_H5 = "wechatH5"; + public static final String PAGE_TYPE_ALIPAY_H5 = "alipayH5"; + public static final String PAGE_TYPE_WECHAT_LITE = "wechatLite"; + public static final String PAGE_TYPE_ALIPAY_LITE = "alipayLite"; + public static final String PAGE_TYPE_YSFPAY_H5 = "ysfpayH5"; + + + /** 入口 **/ + public static final String ENTRY_PAGE_DEFAULT = "default"; + public static final String ENTRY_PAGE_H5 = "h5"; + public static final String ENTRY_PAGE_LITE = "lite"; + + /** 进入小程序支付入口 **/ + public static final String ENTRY_LITE_WXAPP = "wxapp"; + public static final String ENTRY_LITE_ALIAPP = "aliapp"; + public static final String ENTRY_LITE_WXH5 = "wxh5"; + public static final String ENTRY_LITE_ALIH5 = "alih5"; + public static final String ENTRY_LITE_ALIJSAPIH5 = "aliJsapih5"; /** 服务窗方式 **/ + /** **/ + public static final String ENTRY_LITE_WX_TG_H5 = "wxTgH5"; + + public static final String CONFIG_MARKETING_TYPE = "marketingConfig"; + + private String id; + + private Byte type; + + private String pageType; + + private Long amt; + + private String tk; + + public QRCodeParams(String sourceId,Byte type, Long amt) { + this.id = sourceId; + this.type = type; + this.amt = amt; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/WxAppletParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/WxAppletParams.java new file mode 100644 index 0000000..3923afc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/WxAppletParams.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.core.model; + +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * 微信托管支付参数 + * @author crystal + * @date 2023/11/29 11:03 + */ +@Data +public class WxAppletParams { + + + private String appid; + + private String code; + + private QRCodeParams qrCodeParams; + + public void preCheck(QRCodeParams qrCodeParams) { + if(StringUtils.isEmpty(code)){ + throw new BizException("缺失[code]参数"); + } + if(StringUtils.isEmpty(appid)){ + throw new BizException("缺失[appid]参数"); + } + this.qrCodeParams = qrCodeParams; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/alipay/AlipaySpOperationInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/alipay/AlipaySpOperationInfo.java new file mode 100644 index 0000000..7c50275 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/alipay/AlipaySpOperationInfo.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.core.model.alipay; + +import lombok.Data; + +/** + * 支付宝代运营授权信息 + * @author zx + * @date 2023-03-13 + */ +@Data +public class AlipaySpOperationInfo { + + public static final String MCH_CONFIG_KEY = "alipaySpOperation"; // 商户配置表 支付宝服务商代运营授权信息配置key + + public static final String HANDLE_STATUS_SUCCESS = "SUCCESS"; // 代运营授权成功 + public static final String HANDLE_STATUS_PROCESS = "PROCESS"; // 代运营授权确认中 + + /** + * 支付宝授权类型,qrcode-扫码授权 apply-发送支付宝授权消息 + */ + private String authType; + + /** + * 支付宝授权账号 + */ + private String alipayAccount; + + /** + * 支付宝商户号。间连场景为商户smid,直连场景为商户支付宝pid + */ + private String merchantNo; + + /** + * 代运营操作结果。 + * SUCCESS:代表成功。 + * PROCESS:待商家确认中。 + * NO_PERMISSION:表示当前商家支付宝账号无权限操作。需要提醒商家切换成发起授权时指定的支付宝账号。 + * NONE:表示不存在代运营绑定或授权关系。 + * NONE_ACCOUNT:间连商家推荐支付宝账号列表为空。 + */ + private String handleStatus; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AlipayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AlipayApplymentInfo.java new file mode 100644 index 0000000..90e1fcc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AlipayApplymentInfo.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.core.model.applyment; + +import lombok.Data; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@Data +public class AlipayApplymentInfo extends ApplymentBasicInfo { + + public static Byte PRODUCT_TYPE_OFFLINE = 1; + public static Byte PRODUCT_TYPE_APP = 2; + public static Byte PRODUCT_TYPE_FACE = 3; + public static Byte PRODUCT_TYPE_PHONE_WAP = 4; + public static Byte PRODUCT_TYPE_PC_WAP = 5; + + /** 支付宝账号 **/ + public String accountNo; + + /** 开通产品类型 1-当面付 2-APP支付 3-刷脸付 4-手机网站 5-电脑网站 **/ + public Byte productType; + + /** 特殊资质证书 **/ + protected String specialLicenseImg; + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertPaywayFeeList2String(){ + + if(this.paywayFeeList == null){ + return null; + } + + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 单笔费率配置 + if (PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())) { + return convertRate(paywayFee.getFeeRate()).toString(); + } + } + return null; + } + + private BigDecimal convertRate(BigDecimal rate) { + return rate == null ? null : rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP); + } + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AllinpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AllinpayApplymentInfo.java new file mode 100644 index 0000000..8ceba5a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AllinpayApplymentInfo.java @@ -0,0 +1,325 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; + +@Data +public class AllinpayApplymentInfo extends ApplymentBasicInfo { + + /** 客服电话 **/ + private String servicephone; + + /** 结算方式 0-商户自主提现 1-结算到银行卡 2-结算到通联账户 **/ + private String clearMode; + + /** 卡折类型 00-借记卡 01-存折 **/ + private String accttp; + + /** 所属银行 **/ + private String bankcode; + + /** 支行行号 **/ + private String cnapsno; + + /** 经营场所证明文件 url [个人必填] **/ + private String bizplacepic; + + /** 拓展人 **/ + private String expanduser; + + /** 股东身份证人像面 [非个人必填] **/ + private String holderIdcard1Img; + + /** 控股股东姓名 [非个人必填] **/ + private String holdername; + + /** 控股股东身份证号 [非个人必填] **/ + private String holderidno; + + /** 控股股东身份证有效期 [非个人必填] **/ + private String holderexpire; + + /** 注册资本 1(<10w) 2(10-20w) 3(20-50w) 4(50-100w) 5(>100w) [非个人必填] **/ + private String registerfund; + + /** 员工人数 1(<10) 2(10-20) 3(20-50) 4(50-100) 5(>100) [非个人必填] **/ + private String stafftotal; + + /** 经营区域 1-城区 2-郊区 3-边远地区 [非个人必填] **/ + private String operatelimit; + + /** 经营地段 1-商业区 2-工业区 3-住宅区 [非个人必填] **/ + private String inspect; + + /** 是否为三证合一 1-是 0-否 默认:1 **/ + private String thrcertflag; + + /*** 对公账户信息 [企业对私必填] 格式:对公账户号#支付行号#对公账户名称 */ + private String pubacctinfo; + + /*** 业务场景 0-线下 1-线上 默认0 */ + private String offlag; + + /*** 网站url/下载地址/平台名称 [开通网关(含B2B、APP)、快捷、云闪付APP或线上场景必填] */ + private String cusurl; + + /*** 网站名称/应用名称 [开通网关(含B2B、APP)、快捷、云闪付APP或线上场景必填] */ + private String webname; + + /** 法人手机号 **/ + private String persontel; + + /** 性别 1-男 2-女 **/ + private String idcardSex; + /** 职业 + * 1-国家机关、党群组织、企业、事业单位人员 + * 2-专业技术人员 + * 3-办事人员和有关人员 + * 4-商业、服务业人员 + * 5-农、林、牧、渔、水利业生产人员 + * 6-生产、运输设备操作人员及有关人员 + * 7-军人 + * 8-其他 **/ + private String occupation; + + /*** 通联电子账户号 */ + private String tlbankno; + + /*** 经营场所 1-独立门店、连锁店、专卖店 2-综合卖场 3-批发市场 4-其他 */ + private String businessplace; + + /*** 税务登记号 */ + private String taxregcode; + + /*** 税务登记日期 */ + private String taxcodeexpire; + + /*** 税务登记照片 */ + private String taxcodepic; + + /*** 经营内容 */ + private String busdetail; + + /*** 签字授权书 */ + private String authorpic; + + /*** 结算授权书 */ + private String settauthpic; + + + /** 商户类型转换 **/ + public String convertMerchantType() { + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType) { + // 个人 + return "4"; + }else if (MchApplyment.MERCHANT_TYPE_INDIVIDUAL == this.merchantType) { + // 个体户 + return "3"; + }else if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == this.merchantType) { + // 企业 + return "1"; + } + return ""; + } + + /** 结算账户类型 **/ + public String convertSettType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + // 对公 + return "1"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + // 对私 + return "0"; + } + return ""; + } + + /** 门店信息 **/ + public JSONArray covertStoreInfo() { + JSONArray array = new JSONArray(); + JSONObject storeJson = new JSONObject(); + /** 门店编号 进件时,为空 **/ + storeJson.put("branchno", ""); + /** 门店名称 **/ + storeJson.put("branchname", this.mchShortName); + /** 门店地址 **/ + storeJson.put("branchaddr", this.address); + /** 门店联系人 **/ + storeJson.put("contactperson", this.contactName); + /** 联系人电话 **/ + storeJson.put("contactphone", this.contactPhone); + /** 所在区 **/ + storeJson.put("districtcode", this.areaCode.get(2)); + array.add(storeJson); + return array; + } + + /** 法人信息 **/ + public String covertLegal() { + JSONObject legalJson = new JSONObject(); + legalJson.put("persontel", this.persontel); + legalJson.put("nationality", "中国"); + legalJson.put("sex", "男".equals(this.idcardSex) ? "1":"2"); + legalJson.put("occupation", this.occupation); + legalJson.put("personaddr", this.idcardAddress); + return legalJson.toJSONString(); + } + + /** 受益人信息 **/ + public String covertBnf() { + JSONObject bnfJson = new JSONObject(); + // 是否与法人信息一致 当bnfflag为0时json内其他字段为空 + bnfJson.put("bnfflag", "0"); + return bnfJson.toJSONString(); + } + + /** 图片信息 **/ + public String covertPic() { + JSONObject picJson = new JSONObject(); + + if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + /** 银行卡正面照 [账户对私必填] **/ + picJson.put("settlebankpic", this.getSettAccountLicenseImg()); + }else { + /** 开户许可证照片 [账户对公必填] **/ + picJson.put("acctlicensepic", this.getCompanyAccountLicenseImg()); + } + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.getMerchantType() && StringUtils.isNotEmpty(this.getStoreCashierImg())) { + /** 经营者与店铺门头合照 [商户为个人必填] **/ + picJson.put("peasonheadpic", this.getStoreCashierImg()); + } + if (!"1".equals(this.thrcertflag) && StringUtils.isNotEmpty(this.getLicenseImg())) { + /** 组织机构代码证照片 [非三证合一时,可上传组织机构代码证] **/ + picJson.put("orgcodepic", this.getLicenseImg()); + } + + if (StringUtils.isNotEmpty(this.settauthpic)) { + /** 结算账户授权书 [结算账户对私时,且允许法人与结算账户不一致时,必填] **/ + picJson.put("settauthpic", this.getSettauthpic()); + } + if (picJson != null) { + return picJson.toJSONString(); + } + return null; + } + + /** 联行号转所属银行号 **/ + public String covertBankNo(String cnapsno) { + // 联行号不能为空,切长度大于5位 + if (StringUtils.isNotEmpty(cnapsno) && cnapsno.length() > 5) { + // 截取前三位 + return "0" + cnapsno.substring(0, 3); + } + return null; + } + + /** 支付产品 **/ + public JSONArray convertProduct() { + JSONArray array = new JSONArray(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + JSONObject feeJson = new JSONObject(); + // 产品名称 + feeJson.put("pid", "P0001"); + // 交易类型 + feeJson.put("mtrxcode", "VSP551"); + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 借记手续费 + feeJson.put("feerate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记保底 + feeJson.put("lowlimit", AmountUtil.convertCent2Dollar(item.getMinFee())); + // 借记封顶 + feeJson.put("toplimit", AmountUtil.convertCent2Dollar(item.getMaxFee())); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + feeJson.put("creditrate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + } + JSONObject feeJson2 = JSONObject.parseObject(feeJson.toJSONString()); + feeJson2.put("pid", "P0003"); + feeJson2.remove("toplimit"); + +// JSONObject feeJson3 = JSONObject.parseObject(feeJson.toJSONString()); +// feeJson3.put("mtrxcode", "VSP591"); + array.add(feeJson); + array.add(feeJson2); +// array.add(feeJson3); + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject aliJsonFee = new JSONObject(); + // 产品名称 + aliJsonFee.put("pid", "P0003"); + // 交易类型 + aliJsonFee.put("mtrxcode", "VSP511"); + aliJsonFee.put("feerate", convertRate(item.getFeeRate())); + + JSONObject feeJson2 = JSONObject.parseObject(aliJsonFee.toJSONString()); + feeJson2.put("pid", "P0001"); + array.add(aliJsonFee); + array.add(feeJson2); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject wxJsonFee = new JSONObject(); + // 产品名称 + wxJsonFee.put("pid", "P0003"); + // 交易类型 + wxJsonFee.put("mtrxcode", "VSP501"); + // 商户经营类目 + wxJsonFee.put("feerate", convertRate(item.getFeeRate())); + + JSONObject feeJson2 = JSONObject.parseObject(wxJsonFee.toJSONString()); + feeJson2.put("pid", "P0001"); + + array.add(wxJsonFee); + array.add(feeJson2); + } + + }); + } + HashMap productMap = new HashMap<>(); + // 去除重复 + JSONArray resultJson = new JSONArray(); + for (int i = 0; i < array.size(); i++) { + Object json = array.get(i); + + JSONObject jsonParams = JSONObject.parseObject(json.toString()); + String mapKey = jsonParams.getString("pid") + jsonParams.getString("mtrxcode"); + // 重复的配置 + if (productMap.get(mapKey) == null){ + resultJson.add(jsonParams); + } + productMap.put(mapKey, jsonParams); + } + return resultJson; + } + + public static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + + @Override + public String bankBranchNo() { + return cnapsno; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentBasicInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentBasicInfo.java new file mode 100644 index 0000000..c29033c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentBasicInfo.java @@ -0,0 +1,466 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONArray; +import com.jeequan.jeepay.core.annotate.Desensitized; +import com.jeequan.jeepay.core.constants.DesensitizedTypeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/*** + * 进件资料的基本信息 + * + * @author terrfly + * @date 2021/12/30 9:01 + */ +@Data +public class ApplymentBasicInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 标识时间长期有效的值 + **/ + public static final String DATE_FOREVER_VAL = "长期"; + + /** ↓↓↓-- 所属行业和基础信息 --↓↓↓ **/ + + /** + * 行业 mcc 码 + **/ + protected String mccCode; + + protected String mccName; + + /** + * 商户类型:参考 t_mch_applyment + **/ + protected Byte merchantType; + + /** + * 登录账号 + **/ + protected String loginAccount; + + /** + * 联系人姓名 + **/ + @Desensitized(type = DesensitizedTypeEnum.CHINESE_NAME) + protected String contactName; + + /** + * 联系人电话 + **/ + @Desensitized(type = DesensitizedTypeEnum.MOBILE_PHONE) + protected String contactPhone; + + /** + * 法人手机号 + */ + protected String legalPersonPhone; + + /** + * 联系人邮箱 + **/ + @Desensitized(type = DesensitizedTypeEnum.EMAIL) + protected String contactEmail; + + /** + * 联系人身份证号码 + **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + protected String contactIdcardNo; + + /** + * 联系人身份证地址 + **/ + @Desensitized(type = DesensitizedTypeEnum.ADDRESS) + protected String contactIdcardAddress; + + /** + * 非法人结算授权函 + */ + protected String letterOfAuthPic; + + /** + * 联系人身份证有效期起始日期 + **/ + protected String contactIdcardEffectBegin; + + /** + * 联系人身份证有效期结束日期 + **/ + protected String contactIdcardEffectEnd; + + /** + * 联系人身份证正面照 + **/ + protected String contactIdcard1Img; + + /** + * 联系人身份证反面照 + **/ + protected String contactIdcard2Img; + + /** + * 非法人作为联系人时 微信业务办理授权函 + **/ + protected String contactWxAuthImg; + + /** ↑↑↑-- 选择所属行业和基础信息 --↑↑↑ **/ + + /** ↓↓↓-- 经营信息 --↓↓↓ **/ + + /** + * 商户简称 + */ + protected String mchShortName; + + /** + * 商户全称 + **/ + protected String mchFullName; + + /** + * 门头照 + **/ + protected String storeOuterImg; + + /** + * 收银台照片 + **/ + protected String storeCashierImg; + + /** + * 店内环境照片 + **/ + protected String storeInnerImg; + + /** + * 结算 + */ + protected String cashierWithSettlerImg; + + /** + * 省市县编码 (包含省市县三级编码) + **/ + protected JSONArray areaCode; + + /** + * 省市区名称 (包含省市县三级编码) + */ + protected JSONArray areaName; + + /** + * 详细地址 + **/ + protected String address; + + /** + * 不带拼接的字段 + */ + protected String mchAddress; + + /** ↑↑↑-- 经营信息 --↑↑↑ **/ + + /** ↓↓↓-- 经营证件 --↓↓↓ **/ + + /** + * 身份证姓名 + */ + @Desensitized(type = DesensitizedTypeEnum.CHINESE_NAME) + protected String idcardName; + + /** + * 身份证号 + **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + protected String idcardNo; + + /** + * 身份证正面人像面 照片 + **/ + protected String idcard1Img; + + /** + * 身份证国徽面 照片 + **/ + protected String idcard2Img; + + /** + * 身份证地址 + **/ + @Desensitized(type = DesensitizedTypeEnum.ADDRESS) + protected String idcardAddress; + + /** + * 身份证有效期开始时间 + **/ + protected String idcardEffectBegin; + + /** + * 身份证有效期截止时间 + **/ + protected String idcardEffectEnd; + + /** + * 法人手持身份证照片 + **/ + protected String idcardInHandImg; + + /** + * 营业执照编号 + **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + protected String licenseNo; + + + protected String licenseName; + + /** + * 营业执照照片 + **/ + protected String licenseImg; + + /** + * 营业执照注册地址 + **/ + protected String licenseAddress; + + /** + * 营业执照有效期开始时间 + **/ + protected String licenseEffectBegin; + + /** + * 营业执照有效期截止时间 + **/ + protected String licenseEffectEnd; + + /** + * 经营范围,部分通道需要 + */ + protected String licenseScope; + + /** ↑↑↑-- 经营证件 --↑↑↑ **/ + + /** ↓↓↓-- 结算账号 --↓↓↓ **/ + + /** + * 结算账号类型 B:对公,C:对私 + */ + protected String settAccountType; + + /** + * 结算账号名称 + **/ + @Desensitized(type = DesensitizedTypeEnum.CHINESE_NAME) + protected String settAccountName; + + /** + * 结算银行卡账号 + **/ + @Desensitized(type = DesensitizedTypeEnum.BANK_CARD) + protected String settAccountNo; + + /** + * 结算银行名称 + **/ + protected String settAccountBankName; + + /** + * 结算银行编码 + */ + protected String settAccountBankCode; + + /** + * 结算银行开户支行区域编码 + **/ + protected JSONArray settAccountBankBranchAreaCode; + + /** + * 结算银行开户支行区域名称 + **/ + protected JSONArray settAccountBankBranchAreaName; + + /** + * 结算银行开户银行支行名称 + **/ + protected String settAccountBankBranchName; + + /** + * 结算银行开户银行支行联行号 + */ + protected String settAccountBankBranchCode; + + /** + * 银行卡照片 + */ + protected String settAccountLicenseImg; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证号 + **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + protected String settAccountIdcardNo; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证正面人像面 照片 + **/ + protected String settAccountIdcard1Img; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证国徽面 照片 + **/ + protected String settAccountIdcard2Img; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证有效期开始时间 + **/ + protected String settAccountIdcardEffectBegin; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证有效期截止时间 + **/ + protected String settAccountIdcardEffectEnd; + + /** + * 认证账户类型(部分接口需要验证使用): B-对公, C-对私 + **/ +// protected String companyAccountType; + + /** + * 对公(部分接口需要验证使用): 营业执照相同的对公账户名称 + **/ +// protected String companyAccountName; + + /** + * 对公(部分接口需要验证使用):结算银行卡账号 + **/ +// @Desensitized(type = DesensitizedTypeEnum.BANK_CARD) +// protected String companyAccountNo; + + /** + * 对公(部分接口需要验证使用):银行卡名称 + **/ +// protected String companyAccountBankName; + + /** + * 对公(部分接口需要验证使用):银行开户支行区域编码 + **/ +// protected JSONArray companyAccountBankBranchAreaCode; + + /** + * 对公(部分接口需要验证使用):银行开户银行支行名称 + **/ +// protected String companyAccountBankBranchName; + + /** + * 对公(部分接口需要验证使用):开户许可证照片 + */ + protected String companyAccountLicenseImg; + + /** + * @since 2024.02.29 + * 是否为授权结算, 后期接入的通道使用该字段为授权结算的标记 + * Y - 是, N - 否 + */ + protected String authSettle; + + /** ↑↑↑-- 结算账号 --↑↑↑ **/ + + /** + * 是否开通分账 0-否 1-是 + */ + private Byte isDivision; + + /** + * 签约产品费率列表 + **/ + protected List paywayFeeList; + + /** + * 企业受益人信息列表(企业时必传) + **/ + protected List companyBeneficiaryList; + + /** + * 上传图片的缓存map (用作: 修改时, 如果已经上传了该图片则不再重新上传,直接使用缓存中的 mediaId / imgId / photoId) + **/ + protected Map uploadImgCache; + + /** + * 结算方式,D0,D1,T1 + */ + protected String settlementType; + + + public static Class getImplInfoClass(String ifCode) { + + try { + + return (Class) Class.forName("com.jeequan.jeepay.core.model.applyment." + StrUtil.upperFirst(ifCode) + "ApplymentInfo"); + + } catch (Exception e) { + + return null; + + } + } + + /** + * 获取支行联行号,每个渠道目前使用的字段不一致,这里使用统一返回方法 + * @return + */ + public String bankBranchNo() { + return settAccountBankBranchCode; + } + + public String bankAccountName() { + return settAccountName; + } + + /** + * 保存时的数据校验 + */ + public void saveCheck() { + // 添加默认的校验 + Date now = new Date(); + // 30天后 + DateTime nowAfter30 = DateUtil.offsetDay(now, 30); + // yyyyMMdd + String nowAfter30Str = DateUtil.format(nowAfter30, DatePattern.PURE_DATE_FORMAT); + + if (contactIdcardEffectEnd != null && !contactIdcardEffectEnd.equals("长期")) { + if (contactIdcardEffectEnd.replace("-", "").compareTo(nowAfter30Str) < 0) { + throw new BizException("联系人身份证有效期不足30天"); + } + } + + if (idcardEffectEnd != null && !idcardEffectEnd.equals("长期")) { + if (idcardEffectEnd.replace("-", "").compareTo(nowAfter30Str) < 0) { + throw new BizException("法人/经营者身份证有效期不足30天"); + } + } + + if (licenseEffectEnd != null && !licenseEffectEnd.equals("长期")) { + if (licenseEffectEnd.replace("-", "").compareTo(nowAfter30Str) < 0) { + throw new BizException("营业执照有效期不足30天"); + } + } + + if (settAccountIdcardEffectEnd != null && !settAccountIdcardEffectEnd.equals("长期")) { + if (settAccountIdcardEffectEnd.replace("-", "").compareTo(nowAfter30Str) < 0) { + throw new BizException("结算人身份证有效期不足30天"); + } + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentSignInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentSignInfo.java new file mode 100644 index 0000000..9834a32 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ApplymentSignInfo.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.applyment; + +import lombok.Data; + +/*** +* 合同签订信息 +* +* @author terrfly +* +* @since 2022/1/21 10:21 +*/ +@Data +public class ApplymentSignInfo { + + public static final String IMG_TYPE_BASE64 = "base64"; + public static final String IMG_TYPE_IMGURL = "imgUrl"; + public static final String IMG_TYPE_QRCONTENT = "qrContent"; + + /** 签约地址 **/ + private String signUrl; + + /** 图片类型 base64、imgUrl、qrContent **/ + private String imgType; + + /** 认证状态 **/ + private String state; + + /** + * 支付宝/微信子商户号 + */ + private String channelSubMchId; + + /** 原始参数 **/ + private String originData; + + /** 错误信息 **/ + private String errInfo; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AutoConfigMchAppPayInfoResult.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AutoConfigMchAppPayInfoResult.java new file mode 100644 index 0000000..d41d06b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/AutoConfigMchAppPayInfoResult.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; + +/*** +* 进件 商户应用支付参数一键配置结果 +* +* @author zx +* +* @date 2023/9/19 9:41 +*/ +@Data +public class AutoConfigMchAppPayInfoResult { + + /** 一键配置的商户应用AppId **/ + private String appId; + + /** 商户号 **/ + private String mchNo; + + /** 配置结果 1-成功 0-失败 **/ + private Byte state; + + /** 失败信息 **/ + private String errMsg; + + /** 支付参数配置结果 1-成功 0-失败 **/ + private Byte paramsState; + + /** 费率配置结果 1-成功 0-失败 **/ + private Byte rateState; + + /** 通道配置结果 1-成功 0-失败 **/ + private Byte passageState; + + public AutoConfigMchAppPayInfoResult() {} + + public AutoConfigMchAppPayInfoResult(Byte state, Byte paramsState, Byte rateState, Byte passageState) { + this.state = state; + this.paramsState = paramsState; + this.rateState = rateState; + this.passageState = passageState; + } + + public static AutoConfigMchAppPayInfoResult initAllStateFail() { + return new AutoConfigMchAppPayInfoResult(CS.NO, CS.NO, CS.NO, CS.NO); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/BcmpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/BcmpayApplymentInfo.java new file mode 100644 index 0000000..3657daf --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/BcmpayApplymentInfo.java @@ -0,0 +1,266 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class BcmpayApplymentInfo extends ApplymentBasicInfo{ + + /** 客服电话 **/ + private String servicePhone; + + /** 支付宝类目 **/ + private String alipayBusiness; + + /** 微信商户通道费率 **/ + private String wechatFeeRate; + + /** 微信结算规则ID **/ + private String wechatStlmRuleId; + + /** 经营范围 **/ + private String licenseBusiness; + + /** 法人手机号 **/ + private String legalPhone; + + /** 法人职业 **/ + private String legalProfession; + + /** 法人性别 **/ + private String idcardSex; + + /** 行业类别 **/ + private String induPriv; + + /** 注册资金 **/ + private String regCapital; + + /** 组织机构代码证号 **/ + private String orgCertCode; + + /** 授权书 **/ + private String authorization; + + /** 客户经理与授权人合影 **/ + private String groupPhoto; + + /** 联行号 **/ + private String openBankNo; + + /** 清算账户 **/ + private String acctId; + + /** 结算周期 06-全D+0 07-D+0 08-D+0.5 09-D0 01-T+1 02-D+1 03-周结 04-月结 05-D+N **/ + private String cptlStlmPerd; + + /** 手续费结算周期 01-日结 02-月结 03-周结 04-季结 **/ + private String feeStlmPerd; + + /** 账户类型 07-本行对公钱包 08-本行对私钱包 05-他行对公 06-他行对私 01-本行对公 03-本行对私 04-内部户 **/ + private String acctType; + + /** 微信费率规则 **/ + private static final Map WX_BUS_FEE_ID_MAP = new HashMap<>();; + static { + WX_BUS_FEE_ID_MAP.put("757", "0.38%"); + WX_BUS_FEE_ID_MAP.put("758", "0.20%"); + WX_BUS_FEE_ID_MAP.put("759", "0.30%"); + WX_BUS_FEE_ID_MAP.put("764", "0.10%"); + WX_BUS_FEE_ID_MAP.put("765", "0.00%"); + WX_BUS_FEE_ID_MAP.put("771", "1.00%"); + WX_BUS_FEE_ID_MAP.put("760", "0.10%"); + WX_BUS_FEE_ID_MAP.put("761", "0.60%"); + WX_BUS_FEE_ID_MAP.put("762", "0.20%"); + WX_BUS_FEE_ID_MAP.put("763", "0.20%"); + WX_BUS_FEE_ID_MAP.put("766", "0.20%"); + WX_BUS_FEE_ID_MAP.put("767", "0.30%"); + WX_BUS_FEE_ID_MAP.put("768", "0.10%"); + WX_BUS_FEE_ID_MAP.put("769", "0.00%"); + WX_BUS_FEE_ID_MAP.put("770", "0.20%"); + } + + /** 商户类型转换 **/ + public String convertMerchantType() { + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType) { + // 个人 + return "11"; + }else if (MchApplyment.MERCHANT_TYPE_INDIVIDUAL == this.merchantType) { + // 个体户 + return "10"; + }else if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == this.merchantType) { + // 企业 + return "03"; + } + return ""; + } + + /** 截止日期转换 **/ + public String convertDate(String dateStr) { + if ("长期".equals(dateStr)) { + return "99999999"; + } + return dateStr.replace("-", ""); + } + + /** 支付产品 **/ + public void convertProduct(JSONArray array) { + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + JSONObject feeJson = new JSONObject(); + + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 产品名称 + feeJson.put("uf_pay_type", "11"); + feeJson.put("fee_fix", AmountUtil.convertCent2DollarShort(item.getMinFee()+"")); + feeJson.put("fee_up_lmt", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + + // 借记手续费 + feeJson.put("fee_rate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 业务类型 + feeJson.put("buss_type", "13"); + // 计费类型 按百分比 + feeJson.put("fee_type", "1"); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + feeJson.put("fee_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + } + JSONObject feeJson2 = JSONObject.parseObject(feeJson.toJSONString()); + feeJson2.put("uf_pay_type", "12"); + + array.add(feeJson); + array.add(feeJson2); + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject aliJsonFee = new JSONObject(); + // 产品名称 + aliJsonFee.put("uf_pay_type", "11"); + // 业务类型 + aliJsonFee.put("buss_type", "12"); + aliJsonFee.put("fee_type", "1"); + aliJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + + array.add(aliJsonFee); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject wxJsonFee = new JSONObject(); + wxJsonFee.put("uf_pay_type", "11"); + // 业务类型 + wxJsonFee.put("buss_type", "11"); + wxJsonFee.put("fee_type", "1"); + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + array.add(wxJsonFee); + } + + }); + } + } + + /** 支付产品 **/ + public JSONArray converThirdPayList() { + JSONArray array = new JSONArray(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + JSONObject feeJson = new JSONObject(); + // 支付类型 + feeJson.put("third_open_type", "13"); + array.add(feeJson); + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject aliJsonFee = new JSONObject(); + // 支付类型 + aliJsonFee.put("third_open_type", "12"); + // 支付宝类目 + aliJsonFee.put("alipay_business", this.alipayBusiness); + array.add(aliJsonFee); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject wxJsonFee = new JSONObject(); + // 支付类型 + wxJsonFee.put("third_open_type", "11"); + // 微信费率 + wxJsonFee.put("wechat_fee_rate", WX_BUS_FEE_ID_MAP.get(this.wechatStlmRuleId)); + // 微信结算规则ID + wxJsonFee.put("wechat_stlm_rule_id", this.wechatStlmRuleId); + // 商户类型 + wxJsonFee.put("mcht_type", MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType ? "05":MchApplyment.MERCHANT_TYPE_INDIVIDUAL == this.merchantType ? "02":"01" ); + + array.add(wxJsonFee); + } + + }); + } + return array; + } + + /** 产品开通 **/ + public JSONObject productOpen() { + JSONObject bussInfo = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 是否开通银联快捷 +// bussInfo.put("is_open_fast_union", "1"); + // 是否开通银联二维码 + bussInfo.put("is_open_third_union", "1"); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 是否开通支付宝二维码 + bussInfo.put("is_open_third_alipay", "1"); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 是否开通微信二维码 + bussInfo.put("is_open_third_wechat", "1"); + } + }); + } + return bussInfo; + } + + + + public static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + + @Override + public String bankBranchNo() { + return openBankNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/CashoutFee.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/CashoutFee.java new file mode 100644 index 0000000..2e8c940 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/CashoutFee.java @@ -0,0 +1,18 @@ +package com.jeequan.jeepay.core.model.applyment; + +import lombok.Data; + +/*** +* 提现手续费计算 +* +* @author terrfly +* +* @date 2022/3/30 9:41 +*/ +@Data +public class CashoutFee extends PaywayFee{ + + /** 申请提现最低(低于xx不可提现) 单位: 分 */ + private Long applyLimit; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ChannelFeeCalModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ChannelFeeCalModel.java new file mode 100644 index 0000000..5a0e432 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ChannelFeeCalModel.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.alibaba.fastjson.JSON; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 渠道手续费计算方式 +* +* @author terrfly +* +* @date 2023/6/7 14:48 +*/ +@Data +public class ChannelFeeCalModel { + + /** 手续费计算方式: + * 1.基于最新收单金额计算: BASE_FINAL_ORDER_AMOUNT : 手续费退还金额 = 收单手续费 - (订单金额 - 退款金额) X 费率 ( 得到最新的实际支付金额,再计算手续费, 最后减去差值 ) + * 2. 收单金额和退款金额分开计算: SPLIT_PAY_REFUND_AMOUNT: 手续费退还金额 = 收单手续费 - 退款金额 X 费率 ( 依据退款订单金额计算手续费, 目前支付宝采用这种方式。 ) + * + * 对比: + * 1. 基于最新收单金额计算(BASE_FINAL_ORDER_AMOUNT): 优点为比较精准: 每次都已最新的实际收单金额计算。 缺点: 逻辑比较复杂。 + * 2. 收单金额和退款金额分开计算(SPLIT_PAY_REFUND_AMOUNT): 优点为计算简单, 且目前支付宝采用该方式, 缺点: 可能出现 包含实收金额但不收取商家手续费的情况,例如: + * 商家费率0.6%, 订单金额6元, 第一次退款2.5元,第二次退款2.5元, 客户实付 1元 + * 按照 SPLIT_PAY_REFUND_AMOUNT 模式计算 商家实际手续费: 6X0.6% - 2.5X0.6% - 2.5X0.6% = 0.03 - 0.02 - 0.02 = -0.01 = 0 元。 + * 按照 BASE_FINAL_ORDER_AMOUNT 模式计算 商家实际手续费: 1 X 0.6% = 0.01元 手续费。 + * + * 总结:两种模式, 误差不会高于0.01元, 按照实际场景配置即可。 + * 提示: + * 1. 若手续费按照那种方式计算, 服务商的退回也按照该方式进行。 + * 2. 若包含阶梯费率, 那么只能按照: BASE_FINAL_ORDER_AMOUNT 模式计算! SPLIT_PAY_REFUND_AMOUNT模式无只适合单笔费率的计算! + * + * **/ + public static final String FEE_CAL_MODEL_BASE_FINAL_ORDER_AMOUNT = "BASE_FINAL_ORDER_AMOUNT"; + public static final String FEE_CAL_MODEL_SPLIT_PAY_REFUND_AMOUNT = "SPLIT_PAY_REFUND_AMOUNT"; + + private String feeCalModel; + + public static final ChannelFeeCalModel getByDefault(String val){ + + if(StringUtils.isEmpty(val)){ + + ChannelFeeCalModel result = new ChannelFeeCalModel(); + result.setFeeCalModel(FEE_CAL_MODEL_BASE_FINAL_ORDER_AMOUNT); + return result; + } + + return JSON.parseObject(val, ChannelFeeCalModel.class); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/DgpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/DgpayApplymentInfo.java new file mode 100644 index 0000000..1533686 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/DgpayApplymentInfo.java @@ -0,0 +1,577 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.DBApplicationConfig; +import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +@Data +public class DgpayApplymentInfo extends ApplymentBasicInfo { + + /** + * 1:线下反扫 + * 2:线下公众号 + * 3:线下小程序 + * 4:线上公众号 + * 5:线上小程序 + * 12:线上反扫 + * */ + public static final String PAY_SCENE_OFFLINE_BAR = "1"; + public static final String PAY_SCENE_OFFLINE_JSAPI = "2"; + public static final String PAY_SCENE_OFFLINE_LITE = "3"; + public static final String PAY_SCENE_ONLINE_JSAPI = "4"; + public static final String PAY_SCENE_ONLINE_LITE = "5"; + public static final String PAY_SCENE_ONLINE_BAR = "12"; + + /** 企业商户进件请求地址 **/ + public static final String MCH_APPLY_ENT_URL = "/merchant/basicdata/ent"; + /** 个人商户进件请求地址 **/ + public static final String MCH_APPLY_INDV_URL = "/merchant/basicdata/indv"; + /** 商户统一进件请求地址 **/ + public static final String MCH_APPLY_REG_URL = "/merchant/integrate/reg"; + + /** 管理员账号 */ + protected String loginUserName; + + /** 公司类型 1:政府机构 2:国营企业 3:私营企业 4:外资企业 5:个体工商户 6:其它组织 7:事业单位*/ + protected String entType; + + /** 结算银行卡绑定手机号 */ + protected String settAccountBindPhone; + + /** 银行编码 */ + protected String bankCode; + + /** 联行号 */ + protected String branchCode; + + /** 支行名称 */ + protected String branchName; + + /** 客服电话 */ + protected String servicePhone; + + /** 组织机构代码证 */ + protected String orgCodePic; + + /** 税务登记证照片 */ + protected String taxRegPic; + + /** 结算卡反面 */ + protected String settBankCardBackImg; + + /** 授权委托书 */ + protected String authEnturstPic; + + /** D1结算协议图片文件 */ + protected String settleAgreePic; + + /** 经营类型 1-实体 2-虚拟 */ + protected String busiType; + + /** 小票名称 */ + protected String receiptName; + + /** 协议类型 0-电子协议 1-纸质协议 */ + protected String agreementType; + + /** 协议号 */ + protected String agreementNo; + + /** 协议模板号 */ + protected String agreementModel; + + /** 协议模板名称 */ + protected String agreementName; + + /** 商户微信配置 业务开通类型 */ + protected String wxFeeType; + + /** 商户微信配置 授权目录 */ + protected String wxWoaPath; + + /** 商户微信配置 微信小程序APPID */ + protected String wxAppletAppId; + + /** 商户微信配置 渠道号 */ + protected String bankChannelNo; + + /** 【结算配置】 业务类型 */ + protected String cashType; + + /** 【结算配置】 手续费类型 */ + protected String selectFeeType; + + /** 【结算配置】 提现手续费(固定/元) */ + protected String fixAmt; + + /** 【结算配置】 费率(百分比/%) */ + protected String feeRate; + + /** 【结算配置】 结算周期 */ + protected String settleCycle; + + /** 【结算配置】 起结金额 */ + protected String minAmt; + + /** 【结算配置】 留存金额 */ + protected String remainedAmt; + + /** 【微信实名认证】 小微经营类型 */ + protected String microBizType; + + /** 【微信实名认证】 申请单号 */ + protected String applymentId; + + /** 支付宝配置对象 */ + protected JSONArray aliConfList; + + /** 微信配置对象 */ + protected JSONArray wxConfList; + + /** 支付宝费率设置参数 MCC **/ + protected String aliFeeMcc; + + /** (银联pos)商务协议 **/ + protected String bankPic; + + /** 银联商户类别 **/ + protected String unionMchType; + + /** 最大分账比例 0-100 (支持两位小数)**/ + protected String applyRatio; + + /** 经度 **/ + protected String longtude; + + /** 纬度 **/ + protected String latitude; + + /** 商户英文名称 **/ + protected String merEnName; + + /** 法人手机号 **/ + protected String idCardPhone; + + /** 法人邮箱 **/ + protected String idCardEmail; + + /** 注册资本 **/ + protected String regCapital; + + /** 斗拱平台综合支付服务协议 **/ + protected String serviceAgreement; + + /** 【商户】斗拱平台综合支付服务功能及价格确认表(纸质合同版) **/ + protected String priceConfirmation; + + /** 签约人法人授权书 **/ + protected String signAuthFileId; + + /** 商户经营内容 **/ + public String licenseBusiness; + + + public String getCertValidityType(String effectEnd) { + if ("长期".equals(effectEnd)) { + return "1"; + } + return "0"; + } + + public String getApplymentReqUrl() { + String reqUrl = ""; + if (this.getMerchantType() == 1) { + reqUrl = MCH_APPLY_INDV_URL; + }else { + reqUrl = MCH_APPLY_ENT_URL; + } + return reqUrl; + } + + /** 支付宝费率配置 **/ + public List convertAliPayFee(DgpayIsvParams isvParams) { + + ArrayList result = new ArrayList<>(); + ArrayList resultOnline = new ArrayList<>(); + + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.forEach(item -> { + + // 单笔费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject aliJsonFee = new JSONObject(); + aliJsonFee.put("pay_channel_id", isvParams.getZfbChannelNo()); + // 支付场景 + aliJsonFee.put("pay_scene", StringUtils.defaultString(isvParams.getPayScene(), "1")); + // 支付宝费率 + aliJsonFee.put("mcc", this.getMccCode()); + aliJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + result.add(aliJsonFee); + } + + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + // 线上支付费率 + JSONObject aliJsonFee = new JSONObject(); + aliJsonFee.put("pay_channel_id", isvParams.getZfbChannelNo()); + // 支付场景 + aliJsonFee.put("pay_scene", StringUtils.defaultString(isvParams.getPayScene(), "1")); + // 支付宝费率 + aliJsonFee.put("mcc", this.getMccCode()); + aliJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + resultOnline.add(aliJsonFee); + } + }); + } + + if (!resultOnline.isEmpty()) { + return resultOnline; + } + + return result; + } + + /** 微信费率配置 **/ + public List convertWxPayFee(DgpayIsvParams isvParams, WxpayOauth2Params wxpayOauth2Params, DBApplicationConfig dbApplicationConfig) { + + + ArrayList result = new ArrayList<>(); + ArrayList resultOnline = new ArrayList<>(); + + List paywayFeeList = this.paywayFeeList; + + // 支付场景 + String payScene = StringUtils.defaultString(isvParams.getPayScene(), "1"); + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.forEach(item -> { + + // 单笔费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + JSONObject wxJsonFee = new JSONObject(); +// // 商户经营类目 +// wxJsonFee1.put("mcc", this.getMccCode()); + wxJsonFee.put("mcc", this.getMccCode()); + wxJsonFee.put("wx_woa_app_id", wxpayOauth2Params.getAppId()); + wxJsonFee.put("wx_woa_path", dbApplicationConfig.getPaySiteUrl()); + wxJsonFee.put("wx_applet_app_id", wxpayOauth2Params.getLiteAppId()); + switch (item.getWayCode()){ + case CS.PAY_WAY_CODE.WX_BAR: { + if ("1".equals(payScene)) { + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_BAR); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_BAR)); + }else { + // 支付场景 线上 + wxJsonFee.put("pay_scene", PAY_SCENE_ONLINE_BAR); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_ONLINE_BAR)); + // 条码线上不上送 + break; + } + result.add(wxJsonFee); + } + break; + case CS.PAY_WAY_CODE.WX_JSAPI: { + if ("1".equals(payScene)) { + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_JSAPI); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_JSAPI)); + }else { + // 支付场景 线上 + wxJsonFee.put("pay_scene", PAY_SCENE_ONLINE_JSAPI); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_ONLINE_JSAPI)); + } + result.add(wxJsonFee); + } + break; + case CS.PAY_WAY_CODE.WX_LITE: { + if ("1".equals(payScene)) { + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_LITE); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_LITE)); + }else { + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_ONLINE_LITE); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_ONLINE_LITE)); + + } + result.add(wxJsonFee); + } + break; + } + } + + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + // 线上支付费率 + JSONObject wxJsonFee = new JSONObject(); + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_BAR); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_BAR)); + + result.add(wxJsonFee); + + wxJsonFee = new JSONObject(); + + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_JSAPI); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_JSAPI)); + + result.add(wxJsonFee); + + wxJsonFee = new JSONObject(); + + // 支付场景 线下 + wxJsonFee.put("pay_scene", PAY_SCENE_OFFLINE_LITE); + // 手续费 + wxJsonFee.put("fee_rate", convertRate(item.getFeeRate())); + // 费率规则号 + wxJsonFee.put("fee_rule_id", getFeeRuleId(PAY_SCENE_OFFLINE_LITE)); + + result.add(wxJsonFee); + } + }); + } + + if (!resultOnline.isEmpty()) { + return resultOnline; + } + + return result; + } + + /** 银联费率 **/ + public List convertUniPayFee() { + ArrayList list = new ArrayList<>(); + List paywayFeeList = this.paywayFeeList; + JSONObject feeJson = new JSONObject(); + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 手续费类型 03-标准类 + feeJson.put("charge_cate_code", "03"); + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 借记手续费 + feeJson.put("debit_fee_rate_down", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记封顶 + feeJson.put("debit_fee_limit_down", AmountUtil.convertCent2Dollar(item.getMaxFee())); + + // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + // 借记手续费 + feeJson.put("debit_fee_rate_up", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记封顶 + feeJson.put("debit_fee_limit_up", AmountUtil.convertCent2Dollar(item.getMaxFee())); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + // 贷记卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + feeJson.put("credit_fee_rate_down", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + + // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("credit_fee_rate_up", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + } + feeJson.put("mcc", this.getMccCode()); + } + + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + // 线上费率 + feeJson.put("charge_cate_code", "03"); + + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 借记手续费 + feeJson.put("debit_fee_rate_down", convertRate(item.getFeeRate()) + ""); + // 借记封顶 + feeJson.put("debit_fee_limit_down", "20"); + + // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + // 借记手续费 + feeJson.put("debit_fee_rate_up", convertRate(item.getFeeRate()) + ""); + // 借记封顶 + feeJson.put("debit_fee_limit_up", "20"); + // 借记封顶 +// feeJson.put("debit_fee_limit_up", AmountUtil.convertCent2Dollar(item.getMaxFee())); + + // 贷记卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + feeJson.put("credit_fee_rate_down", convertRate(item.getFeeRate()) + ""); + + // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("credit_fee_rate_up", convertRate(item.getFeeRate()) + ""); + + feeJson.put("mcc", this.getMccCode()); + } + + }); + } + + if (StringUtils.isNotEmpty(feeJson.getString("mcc"))) { + list.add(feeJson); + } + return list; + } + + /** 银行卡费率 **/ + public JSONObject convertBankPayFee() { + List paywayFeeList = this.paywayFeeList; + JSONObject feeJson = new JSONObject(); + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.forEach(item -> { + + // 阶梯费率 + if (("AUTO_POS".equals(item.getWayCode()) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType()))) { + // 手续费类型 03-标准类 + feeJson.put("charge_cate_code", "03"); + // 商户经营类目(底层接口) + feeJson.put("mcc", this.getMccCode()); + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 云闪付贷记卡手续费1000以下(%) + feeJson.put("cloud_credit_fee_rate_down", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 云闪付借记卡封顶1000以下(元) + feeJson.put("cloud_debit_fee_limit_down", AmountUtil.convertCent2Dollar(item.getMaxFee())); + + // 借记卡手续费(%) + feeJson.put("debit_fee_rate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记卡封顶值 + feeJson.put("debit_fee_limit", AmountUtil.convertCent2Dollar(item.getMaxFee())); + + // 云闪付借记卡手续费1000以上(%) + feeJson.put("cloud_debit_fee_rate_up", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 云闪付借记卡封顶1000以上(元) + feeJson.put("cloud_debit_fee_limit_up", AmountUtil.convertCent2Dollar(item.getMaxFee())); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + // 贷记卡手续费(%) + feeJson.put("credit_fee_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 云闪付借记卡手续费1000以下(%) + feeJson.put("cloud_debit_fee_rate_down", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 云闪付贷记卡手续费1000以上(%) + feeJson.put("cloud_credit_fee_rate_up", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + } + } + + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + // 云闪付贷记卡手续费1000以下(%) + feeJson.put("cloud_credit_fee_rate_down", convertRate(item.getFeeRate()) + ""); + // 云闪付借记卡封顶1000以下(元) + feeJson.put("cloud_debit_fee_limit_down", "20"); + + // 借记卡手续费(%) + feeJson.put("debit_fee_rate", convertRate(item.getFeeRate()) + ""); + // 借记卡封顶值 + feeJson.put("debit_fee_limit", "20"); + + // 云闪付借记卡手续费1000以上(%) + feeJson.put("cloud_debit_fee_rate_up", convertRate(item.getFeeRate()) + ""); + // 云闪付借记卡封顶1000以上(元) + feeJson.put("cloud_debit_fee_limit_up", "9999"); + + // 贷记卡手续费(%) + feeJson.put("credit_fee_rate", convertRate(item.getFeeRate()) + ""); + // 云闪付借记卡手续费1000以下(%) + feeJson.put("cloud_debit_fee_rate_down", convertRate(item.getFeeRate()) + ""); + // 云闪付贷记卡手续费1000以上(%) + feeJson.put("cloud_credit_fee_rate_up", convertRate(item.getFeeRate()) + ""); + } + + }); + } + return feeJson; + } + + public static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + private String getFeeRuleId(String payScene){ + + if (this.getMerchantType() != null && this.getMerchantType() == 1) { + // 个人 + if ("1".equals(payScene) || "2".equals(payScene) || "3".equals(payScene)) { + return "770"; + }else if ("4".equals(payScene) || "5".equals(payScene)) { + return "775"; + } + }else if (this.getMerchantType() != null && this.getMerchantType() == 3) { + // 企业 + if ("1".equals(payScene) || "2".equals(payScene) || "3".equals(payScene)) { + if ("3".equals(this.entType)) { + return "758"; + }else { + return "762"; + } + }else if ("4".equals(payScene) || "5".equals(payScene)) { + if ("3".equals(this.entType)) { + return "756"; + }else { + return "761"; + } + } + } + return null; + } + + /** 银联小微入驻信息实体 **/ + public String getMicroInfo() { + JSONObject resJson = new JSONObject(); + // 银联商户类别 + resJson.put("mchnt_type", this.getUnionMchType()); + // 商户经度 + resJson.put("mer_lng", this.longtude); + // 商户纬度 + resJson.put("mer_lat", this.latitude); + // 店铺名称 + resJson.put("shop_name", this.mchFullName); + // 商户经营类目 + resJson.put("mcc", this.getMccCode()); + return resJson.toJSONString(); + } + + @Override + public String bankBranchNo() { + return branchCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EasypayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EasypayApplymentInfo.java new file mode 100644 index 0000000..3e79e24 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EasypayApplymentInfo.java @@ -0,0 +1,208 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.model.params.easypay.EasypayIsvParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class EasypayApplymentInfo extends ApplymentBasicInfo { + + public static final String SETTLE_WAY_T1 = "01"; + public static final String SETTLE_WAY_D1 = "02"; + public static final String SETTLE_WAY_D0 = "03"; + + /** 主营业务 **/ + public String businessScope; + /** 注册资本:单位-万元 **/ + public String capital; + /** 开户行行号(对于easypay来说,和联行号值相同) **/ + public String bankCode; + /** 开户行行号(对于easypay来说,和联行号值相同)企业且对公 **/ +// public String companyBankCode; + /** 法人手机号 **/ + public String legalPhone; + /** 结算人手机号 **/ + public String settAccountPhone; + /** 控股股东或实际控制人姓名或名称 **/ + public String controlerName; + /** 控股股东或实际控制人证件号码 **/ + public String controlerLegalCode; + /** 控股股东或实际控制人证件有效期 **/ + public String controlerLegalValidityBegin; + public String controlerLegalValidityEnd; + /** 是否结算到法人 **/ + public byte ifSettToLegal; + /** 持卡人手持银行卡照片 **/ + public String settAccountByHandImg; + + + /** 门牌号照片 **/ + public String houseNumImg; + /** 定位照 **/ + public String locationImg; + /** 协议照片 **/ + public String agreementImg; + /** 清算授权书照片 **/ + public String stlAuthImg; + + /** 到账方式 01 T1, 02 D1, 03 D0 **/ + public String settleWay; + + /** + * 商户类型 0-企业 1-个体户 2-小微 + */ + public String convertMerchantType(){ + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "2"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "1"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "0"; + } + return ""; + } + + /** 截止日期转换 **/ + public String convertDate(String startDateStr, String endDateStr) { + if ("长期".equals(endDateStr)) { + endDateStr = "9999.99.99"; + } else { + endDateStr = endDateStr.replace("-", "."); + } + startDateStr = startDateStr.replace("-", "."); + JSONArray array = new JSONArray(); + array.add(startDateStr); + array.add(endDateStr); + return array.toJSONString(); + } + + + /** 结算账户类型 00-个人;10-对公 **/ + public String convertAccountType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "10"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "00"; + } + // 小微商户默认结算到个人 + return "00"; + } + + /** mcc **/ + public String convertMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[1]; + } + return null; + } + + public void convertApplymentPayFee(EasypayIsvParams isvParams, JSONArray funcInfo) { + // 微信业务申请信息 + JSONObject wxJson = new JSONObject(); + // 支付宝业务申请信息 + JSONObject aliJson = new JSONObject(); + // 银行卡/银联二维码业务申请信息 标准类 >1000 + JSONObject bankJson = new JSONObject(); + // 银行卡/银联二维码业务申请信息 营销类 <1000 + JSONObject bankLowJson = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + wxJson.put("funcId", "3"); + wxJson.put("calcVal", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + aliJson.put("funcId", "2"); + aliJson.put("calcVal", convertRate(item.getFeeRate()) + ""); + if (StringUtils.isNotEmpty(isvParams.getAliAppId())){ + aliJson.put("appid", isvParams.getAliAppId()); + } + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 14 营销类<1000 + bankLowJson.put("funcId", "14"); + // 12 标准类>1000 + bankJson.put("funcId", "12"); + // 借记卡手续费最低值(单位:元) 营销类 + bankLowJson.put("DFeeLowLimit", AmountUtil.convertCent2DollarShort(item.getMinFee()+"")); + // 借记卡手续费最低值(单位:元) 标准类 + bankJson.put("DFeeLowLimit", AmountUtil.convertCent2DollarShort(item.getMinFee()+"")); + // 银行卡借记卡费率 单位为% 营销类 + bankLowJson.put("DCalcVal", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 银行卡借记卡费率 单位为% 标准类 + bankJson.put("DCalcVal", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 银行卡借记卡手续费封顶 + if (StringUtils.isEmpty(item.getMaxFee().toString())){ + // 借记卡扣率方式 :1-封顶;0-不封顶 营销类 + bankLowJson.put("DStlmType", "0"); + // 借记卡扣率方式 :1-封顶;0-不封顶 标准类 + bankJson.put("DStlmType", "0"); + } else { + bankLowJson.put("DStlmType", "1"); + bankJson.put("DStlmType", "1"); + // 借记卡封顶金额(单位:元),借记卡扣率方式封顶时必填 营销类 + bankLowJson.put("DStlmMaxAmt", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + // 借记卡封顶金额(单位:元),借记卡扣率方式封顶时必填 标准类 + bankJson.put("DStlmMaxAmt", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + } + } + // 贷记卡费率(信用卡) + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 信用卡扣率(单位:%) 营销类<1000 + bankLowJson.put("CCalcVal", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 信用卡扣率(单位:%) 标准类>1000 + bankJson.put("CCalcVal", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + // 信用卡手续费最低值(单位:元) 营销类 + bankLowJson.put("CFeeLowLimit", AmountUtil.convertCent2DollarShort(item.getMinFee()+"")); + // 信用卡手续费最低值(单位:元) 标准类 + bankJson.put("CFeeLowLimit", AmountUtil.convertCent2DollarShort(item.getMinFee()+"")); + } + } + }); + } + + if (wxJson.size() != 0){ + funcInfo.add(wxJson); + } + if (aliJson.size() != 0){ + funcInfo.add(aliJson); + } + if (bankJson.size() != 0){ + funcInfo.add(bankJson); + } + if (bankLowJson.size() != 0){ + funcInfo.add(bankLowJson); + } + } + + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return bankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EpspayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EpspayApplymentInfo.java new file mode 100644 index 0000000..b69a08a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/EpspayApplymentInfo.java @@ -0,0 +1,309 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +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.params.epspay.EpspayIsvParams; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class EpspayApplymentInfo extends ApplymentBasicInfo { + /** D1增值费用类型 0按笔 1按比例 **/ + public static final Byte HOLIDAY_TYPE_PER = 0; + public static final Byte HOLIDAY_TYPE_RATE = 1; + + /** 结算周期常量 **/ + public static final String SETTLE_WAY_D0 = "D+0"; + public static final String SETTLE_WAY_D1 = "D+1"; + public static final String SETTLE_WAY_T0 = "T+0"; + public static final String SETTLE_WAY_T1 = "T+1"; + + /** 证照商户名称 **/ + private String businessLicenseName; + /** 经营范围 **/ + private String licenseBusiness; + /** 注册地址 **/ + public String registerAddress; + + /** + * 法人手机号码 + **/ + public String legalPersonPhone; + + /** + * 微信经营类目 + **/ + public String wxMccCode; + /** + * 支付宝经营类目(支付宝-MCC) + **/ + public String aliMccCode; + + /** 预留手机号 **/ + public String prePhone; + + /** 结算账户附件 **/ + public String settleAttachment; + /** 客服电话 **/ + public String serviceTel; + + /** 是否已签约协议书 **/ + public String contractStatus; + /** 协议书盖章页/签名页附件 **/ + public String contractAttachment; + /** 转账功能开通申请书附件 **/ + public String transferApplyAttachment; + + /** 开户行联行号 **/ + public String openBankCode; + /** 证明文件 **/ + public String openingLicenseAccountPhoto; + + /** 分账收单手续费类型 1-按平台商费率收取,2-按交易主体费率收取 **/ + public String splitOriTradeFee; + + /** 节假日垫资费率方式 0:按单笔收费;1:按比例收费;结算周期 D+1 时有效 **/ + public String holidayType; + + /** 节假日垫资费率方式 isv:使用服务商的配置 mch:给商户单独配置 **/ + public String holidayTypeConfig; + + /** + * 注册资本 单位:元 + **/ + public Long registeredCapital; + + // 支付方式分类Code + public static final Map PAY_WAY_CODE_MAP = new HashMap<>(); + + static { + // 支付宝支付业务 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.ALI_JSAPI, "ALI_JSAPI_PAY"); // 支付宝生活号支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.ALI_LITE, "ALI_JSAPI_PAY"); // 支付宝小程序支付(实际上是:支付宝生活号支付) + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.ALI_BAR, "ALI_MICRO_PAY"); // 支付宝被扫支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.ALI_QR, "ALI_NATIVE_PAY"); // 支付宝主扫支付 + // 微信支付业务 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.WX_JSAPI, "WX_JSAPI_PAY"); // 微信公众号支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.WX_LITE, "WX_MINI_PROGRAM"); // 微信小程序支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.WX_BAR, "WX_MICRO_PAY"); // 微信被扫支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.WX_NATIVE, "WX_NATIVE_PAY"); // 微信主扫支付 + // 银联支付业务 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.UP_JSAPI, "UNION_JS"); // 银联二维码 JS 支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.YSF_JSAPI, "UNION_JS"); // 银联二维码 JS 支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.UP_BAR, "UNION_ONLINE"); // 银联二维码被扫支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.YSF_BAR, "UNION_ONLINE"); // 银联二维码被扫支付 + PAY_WAY_CODE_MAP.put(CS.PAY_WAY_CODE.UP_QR, "UNION_SWEEP"); // 银联二维码主扫支付 + } + + // 分账业务 + public static final String TRADE_SPLIT = "TRADE_SPLIT"; // 交易分账 + public static final String ACCOUNT_SPLIT = "ACCOUNT_SPLIT"; // 账户分账 + public static final String ORDER_SPLIT = "ORDER_SPLIT"; // 拆单分账 + + // 提现&代付业务 + public static final String WITHDRAW = "WITHDRAW"; // 代付到储蓄卡 + public static final String WITHDRAW_CREDIT_CARD = "WITHDRAW_CREDIT_CARD"; // 代付到信用卡 + public static final String WITHDRAW_TO_SETTMENT_CREDIT = "WITHDRAW_TO_SETTMENT_CREDIT"; // 提现到信用卡 + public static final String WITHDRAW_TO_SETTMENT_DEBIT = "WITHDRAW_TO_SETTMENT_DEBIT"; // 提现到储蓄卡 + + + /** + * 主体类型 1:个体工商户;2:企业;3:个人(小微);4:政府事业单位;9:其他组织 + */ + public String convertMerchantType(){ + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "3"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "1"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "2"; + } + return ""; + } + + // 有效期转换 + public String coverDateTime(String dateStr) { + if ("长期".equals(dateStr)) { + return dateStr; + } else { + return dateStr.replace("-", ""); + } + } + + + /** 结算账户类型 1:对公账户 2:法人账户 3:授权对公 4:授权对私 **/ + public String convertAccountType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "1"; + }else if ("B2".equals(this.getSettAccountType())) { + return "3"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "2"; + }else if ("C2".equals(this.getSettAccountType())) { + return "4"; + } + return ""; + } + + /** + * 收单类商户使用,费率相关业务信息 + **/ + public List convertApplymentPayFee(EpspayIsvParams epspayIsvParams) { + // 业务信息集合,使用map为了去重 + Map businessListMap = new HashMap<>(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 业务代码 + rateJson(CS.YES, businessListMap, epspayIsvParams, PAY_WAY_CODE_MAP.get(item.getWayCode()), null, convertRate(item.getFeeRate()), null, null); + } + + // 阶梯费率(文档中没有明确划分借贷记,暂按借记卡取值 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + rateJson(CS.YES, businessListMap, epspayIsvParams, PAY_WAY_CODE_MAP.get(item.getWayCode()), item.getMinFee(), convertRate(item.getLevelList().get(0).getFeeRate()), item.getMaxFee(), convertRate(item.getLevelList().get(1).getFeeRate())); + } + // 贷记卡费率 +// if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { +// rateList(businessList, epspayIsvParams, PAY_WAY_CODE_MAP.get(item.getWayCode()), item.getCreditCardPaywayFee().getMinFee(), convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()), item.getCreditCardPaywayFee().getMaxFee(), convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); +// } + } + }); + } + // 交易分账 + rateJson(CS.NO, businessListMap, epspayIsvParams, TRADE_SPLIT, null, 0L, null, null); + + // 提现&代付业务 + rateJson(CS.NO, businessListMap, epspayIsvParams, WITHDRAW, null, 0L, null, null); + rateJson(CS.NO, businessListMap, epspayIsvParams, WITHDRAW_TO_SETTMENT_DEBIT, null, 0L, null, null); + + return new ArrayList<>(businessListMap.values()); + } + + /** + * 非收单类商户使用,提现信息 + **/ + public List convertApplymentPaySplit(EpspayIsvParams epspayIsvParams) { + // 业务信息集合,使用map为了去重 + Map businessListMap = new HashMap<>(); + // 提现&代付业务 + rateJson(CS.NO, businessListMap, epspayIsvParams, WITHDRAW, null, 0L, null, null); + rateJson(CS.NO, businessListMap, epspayIsvParams, WITHDRAW_TO_SETTMENT_DEBIT, null, 0L, null, null); + + return new ArrayList<>(businessListMap.values()); + } + + /** 费率转换 **/ + public static Long convertRate(BigDecimal rate) { + return rate == null ? null : Long.valueOf(String.valueOf(rate.multiply(new BigDecimal(10000)).setScale(0, BigDecimal.ROUND_HALF_UP))); + } + + /** 将服务商填写的D1附加费率或单笔手续费*100 **/ + public static Long convertStrToLong(String str) { + if (StringUtils.isNotEmpty(str)) { + return new BigDecimal(str).multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue(); + } + return null; + } + + /** + * 业务申请信息:business 模式 ifRate 1 比例 0单笔 + */ + private void rateJson(Byte ifRate, Map businessListMap, EpspayIsvParams epspayIsvParams, String businessCode, Long feeMin, Long minRate, Long feeMax, Long maxRate) { + if (businessCode == null) { + return; + } + JSONObject businessJson = new JSONObject(); + // 业务代码 + businessJson.put("businessCode", businessCode); + // 手续费费率 + businessJson.put("stage", setStageList(ifRate, minRate, maxRate)); + // 保底手续费 LONG 默认无保底手续费 + if (feeMin != null) { + businessJson.put("feeMin", feeMin); + } + + // 封顶手续费 默认上不封顶 + if (feeMax != null) { + businessJson.put("feeMax", feeMax); + } + + // 允许退款 0:不允许;1:允许 + businessJson.put("refundEnabled", "1"); + // 是否允许信用卡支付 0:禁用,1:允许;默认 0 + businessJson.put("creditcardsEnabled", "1"); + + // 结算周期 + businessJson.put("settleCycle", epspayIsvParams.getSettleWay()); + // 分账收单手续费类型 1-按平台商费率收取,2-按交易主体费率收取 非必填 +// businessJson.put("splitOriTradeFee", ""); + if (epspayIsvParams.getSettleWay().equals(SETTLE_WAY_D1)) { + // 节假日垫资费率方式 0:按单笔收费;1:按比例收费;结算周期 D+1 时有效 + businessJson.put("holidayType", epspayIsvParams.getHolidayType()); + if (epspayIsvParams.getHolidayType().equals(HOLIDAY_TYPE_PER)) { + // D1 交易节假日附加收费的单笔加收费用 单位为分. 比如 3 表示 3 分。结算周期 D+1 时有效,与holidayRate 二选一 + businessJson.put("holidayPer", convertStrToLong(epspayIsvParams.getHolidayPer())); + } else if (epspayIsvParams.getHolidayType().equals(HOLIDAY_TYPE_RATE)) { + // D1 交易节假日附加收费的费率 万份比.比如值为 200,表示万分之200,即百二。结算周期 D+1 时有效,与 holidayPer 二选一 + businessJson.put("holidayRate", convertStrToLong(epspayIsvParams.getHolidayRate())); + } + } + businessListMap.put(businessCode, businessJson); + } + + /** + * 业务申请信息:business + */ + private List setStageList(Byte ifRate, Long minRate, Long maxRate) { + List stageList = new ArrayList<>(); + JSONObject stageJson = new JSONObject(); + if (ifRate == CS.YES) { + // 按比例收费 根据交易金额的比率收费, 单位”万分比”.例:万二三的费率,传 23 即可 + stageJson.put("feeRate", minRate); + } else { + // 单笔交易计费,单位”分/笔”。feeRate 与 feePer 都传即为混合计费 + stageJson.put("feePer", 0); + } + // 阶梯起始交易金额 默认 0,闭区间,满足条件:交易金额>amountFrom AND 交易额 <= 下一阶梯的 amountFrom + stageJson.put("amountFrom", 0); + + stageList.add(stageJson); + if (maxRate != null) { + JSONObject stageMaxJson = new JSONObject(); + // 按比例收费 根据交易金额的比率收费, 单位”万分比”.例:万二三的费率,传 23 即可 + stageMaxJson.put("feeRate", maxRate); + // 阶梯起始交易金额 默认 0,闭区间,满足条件:交易金额>amountFrom AND 交易额 <= 下一阶梯的 amountFrom + stageMaxJson.put("amountFrom", 1000); + stageList.add(stageMaxJson); + } + return stageList; + } + + /** + * MCC + **/ + public String coverMcc(String mccCode) { + if (StringUtils.isNotEmpty(mccCode)) { + String[] split = mccCode.split("_"); + return split[1]; + } + return null; + } + + @Override + public String bankBranchNo() { + return openBankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/FuioupayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/FuioupayApplymentInfo.java new file mode 100644 index 0000000..2776e9a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/FuioupayApplymentInfo.java @@ -0,0 +1,146 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.model.params.fuioupay.FuioupayConfig; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; + +@EqualsAndHashCode(callSuper = true) +@Data +public class FuioupayApplymentInfo extends ApplymentBasicInfo{ + + /** 联系人身份证件号码 */ + protected String contactCertNo; + + /** 证件类型 */ + protected String licenseType; + + /** 营业执照注册地址 */ + protected String licRegisAddr; + + /** 法人入账标识 */ + protected String acntArtifFlag; + + /** 入账证件号 */ + protected String acntCertifId; + + /** 入账证件到期日(格式 yyyyMMdd) */ + protected String acntCertifExpireDt; + + /** 清算类型 */ + protected String settleTp; + + /** 清算类型扣率 */ + protected String settleTpCd; + + /** 清算时间 */ + protected String settleTs; + + /** 微信支付标识(0:不开通,1:开通) */ + protected String wxFlag; + + /** 支付宝支付标识(0:不开通,1:开通) */ + protected String aliFlag; + + /** 客服电话 */ + protected String servicePhone; + + /** 入账卡开户行联行号 */ + protected String interBankNo; + + /** 入账非法人证明照片 **/ + protected String acntArtifImg; + + /** 组织机构代码证照片 **/ + protected String organizationImg; + + /** 税务登记证照片 **/ + protected String taxRegistrationImg; + + /** 手持证件照片 **/ + protected String handCertificateImg; + + /** 补充资料照片 **/ + protected String additionImg; + + + public String convertIdcardEffectBegin() { + return idcardEffectBegin.replaceAll("-", ""); + } + + public String convertIdcardEffectEnd() { + return "长期".equals(idcardEffectEnd) ? "20991231" : idcardEffectEnd.replaceAll("-", ""); + } + + public String convertLicenseEffectBegin() { + return licenseEffectBegin.replaceAll("-", ""); + } + + public String convertLicenseEffectEnd() { + return "长期".equals(licenseEffectEnd) ? "20991231" : "无有效期".equals(licenseEffectEnd) ? "19000101" : licenseEffectEnd.replaceAll("-", ""); + } + + public String covertAcntCertifExpireDt() { + return StringUtils.isNotBlank(acntCertifExpireDt) ? "长期".equals(acntCertifExpireDt) ? "20991231" : acntCertifExpireDt.replaceAll("-", "") : ""; + } + + public String covertSettAccountType() { + return settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE) ? "1" : "2"; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertPaywayFeeList2SettleTpCode(String rateType){ + + if(this.paywayFeeList == null){ + return null; + } + + String rate = getRate(rateType); + if (StringUtils.isBlank(rate)) { + return null; + } + + return FuioupayConfig.SETTLE_TP_CODE_MAP.get(rate); + } + + /** 获取配置的费率 */ + private String getRate(String rateType) { + + String rate = null; + + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 微信费率 + if ("wxpay".equals(rateType) && paywayFee.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())) { + rate = convertRate(paywayFee.getFeeRate()); + break; + + // 支付宝费率 + } else if ("alipay".equals(rateType) && paywayFee.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())) { + rate = convertRate(paywayFee.getFeeRate()); + break; + + // 单笔费率配置 + } else { + if (PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())) { + rate = convertRate(paywayFee.getFeeRate()); + break; + } + } + } + + return rate; + } + + private String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return interBankNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HkpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HkpayApplymentInfo.java new file mode 100644 index 0000000..25483c0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HkpayApplymentInfo.java @@ -0,0 +1,160 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.model.params.hkpay.HkpayIsvParams; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class HkpayApplymentInfo extends ApplymentBasicInfo { + public static final String SETTLE_WAY_T1 = "01"; + public static final String SETTLE_WAY_D1 = "02"; + public static final String SETTLE_WAY_D0 = "03"; + + /** 门店名称(商户门头名称) **/ + public String shopName; + + /** 结算账户清算行号(对于hkpay来说,和行联号值相同) **/ + public String bankCode; + + /** 预留手机号 **/ + public String prePhone; + + /** 是否结算到法人 **/ + public byte ifSettToLegal ; + + /** 营业执照所在地省市县编码 (包含省市县三级编码) **/ + public JSONArray licenseAreaCode; + + /** 第二张营业场所室内照图片 **/ + public String storeInner2Img; + + /** 非法人&对私 结算授权函图片 **/ + public String stlAuthImg; + + /** 非法人&对私 法人手持结算授权函合影图片 **/ + public String legalHandStlAuthImg; + + /** 结算周期 01 T1, 02 D1, 03 D0 **/ + public String settleWay; + + + /** + * 商户类型 10A:个体工商户 10B:企业 10C:小微商户 + */ + public String convertMerchantType(){ + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "10C"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "10A"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "10B"; + } + return ""; + } + + + /** 结算账户类型 10A:对公 10B:对私 **/ + public String convertAccountType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "10A"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "10B"; + } + return ""; + } + + /** mcc转换 **/ + public String convertMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] code = this.mccCode.split("_"); + return code[1]; + } + return null; + } + + + public JSONObject convertApplymentPayFee(HkpayIsvParams isvParams) { + // 微信业务申请信息 + JSONObject wxJson = new JSONObject(); + // 支付宝业务申请信息 + JSONObject aliJson = new JSONObject(); + // 银行卡/银联二维码业务申请信息 + JSONObject bankJson = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + wxJson.put("channel_no", isvParams.getChannelNoWx()); + wxJson.put("rate", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + aliJson.put("channel_no", isvParams.getChannelNoAli()); + aliJson.put("rate", convertRate(item.getFeeRate()) + ""); + } + + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 银行卡借记卡费率 +// bankJson.put("bank_debit_rate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 银行卡借记卡手续费封顶 +// bankJson.put("bank_debit_max", item.getMaxFee().toString() + ""); + // 银联二维码借记卡费率 + bankJson.put("union_debit_rate", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 银联二维码借记卡手续费封顶 + bankJson.put("union_debit_max", item.getMaxFee().toString() + ""); + + } + // 贷记卡费率 + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 银行卡贷记卡费率 +// bankJson.put("bank_credit_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 银联二维码贷记卡费率 + bankJson.put("union_credit_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + // 银联二维码1000以下包括1000费率值 + bankJson.put("union_mix_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + } + + } + }); + } + JSONObject productData = new JSONObject(); + if (!wxJson.isEmpty()){ + productData.put("wx", wxJson); + } + if (!aliJson.isEmpty()){ + productData.put("ali", aliJson); + } + if (!bankJson.isEmpty()){ + productData.put("bank", bankJson); + } + + return productData; + } + + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(10000)).setScale(0, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return bankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HmpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HmpayApplymentInfo.java new file mode 100644 index 0000000..7ef4efd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HmpayApplymentInfo.java @@ -0,0 +1,217 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class HmpayApplymentInfo extends ApplymentBasicInfo{ + + public static String HM_MERCHANT_TYPE_GENERAL = "GENERAL_MERCHANT"; + public static String HM_MERCHANT_TYPE_PERSONAL = "PERSONAL_MERCHANT"; + + /** 银行账户类型 PUBLIC_ACCOUNT-对公帐户 PRIVATE_DEBIT_ACCOUNT-对私借记卡 **/ + public static String HM_BANK_ACCOUNT_TYPE_PUBLIC = "PUBLIC_ACCOUNT"; + public static String HM_BANK_ACCOUNT_TYPE_PERSONAL = "PERSONAL_MERCHANT"; + + /** 支付方式 WEIXIN:微信 ALIPAY:支付宝 UNION_PAY:银联支付SANDBAO:杉德宝 **/ + public static String HM_PAY_WAY_WEIXIN = "WEIXIN"; + public static String HM_PAY_WAY_ALIPAY = "ALIPAY"; + public static String HM_PAY_WAY_UNION_PAY = "UNION_PAY"; + public static String HM_PAY_WAY_SANDBAO = "SANDBAO"; + + /** 商户类型 普通商户:GENERAL_MERCHANT 个人小微:PERSONAL_MERCHANT **/ + public String hmMerchantType; + + /** 小微经营类型 **/ + public String microBizType; + + /** 工商网截图 **/ + public String icNetScreenShot; + + /** 单位证明照 **/ + public String companyProveImgUrl; + + /** 企业性质 股份有限公司:STOCK_COMPANY 有限公司:LIMITED_COMPANY 个体工商户:INDIVIDUAL_BUSINESS 事业单位:GOVERNMENT_INSTITUTION 其他:OTHER **/ + public String enterpriseNature; + + /** 注册地址 **/ + public String registerAddress; + + /** 联系人类型 **/ + public String contactPersonType; + + /** 联系人身份证号 **/ + public String contactPersonIdCardNo; + + /** 法人性别 **/ + public String idcardSex; + + /** 联系人性别 **/ + public String contactPersonSex; + + /** 客服电话 **/ + public String serviceTel; + + /** 支付方式详情 **/ + public String payWayInfo; + + /** 租赁协议(小微使用) **/ + public String leaseAgreement; + + /** 其它补充图片 小微不能超过5个(目前租赁协议占了一个) 普通商户不能超过10个 **/ + public String otherPicUrl1; + public String otherPicUrl2; + public String otherPicUrl3; + + + /** 商户类别 用于开通支付产品(支付宝和银联) **/ + public String mccTypeCode; + /** 微信经营类目 开通微信支付时必填 **/ + public String wxMccCode; + + /* 绑卡信息 **/ + /** 银行账户类型 个人小微商户只能选择对私账户 PUBLIC_ACCOUNT:对公帐户 PRIVATE_DEBIT_ACCOUNT:对私借记卡 **/ + public String bankAccountType; + /** 银行联行号 对公账户必填 **/ + public String bankChannelNo; + /** 银行开户身份证号码 对私账户必填 **/ + public String bankAccountIdCardNo; + /** 银行预留手机号 对私账户必填 **/ + public String bankAccountPhone; + /** 商户换卡必填 换卡生效时间 **/ + public String validDate; + + + /** + * 分账计费模式 + **/ + public String feeType; + + public String convertIdCardStartEnd(String idcardEffectBegin, String idcardEffectEnd){ + JSONObject jsonObject = new JSONObject(); + jsonObject.put("start_date", idcardEffectBegin); + if ("长期".equals(this.getIdcardEffectEnd())) { + jsonObject.put("end_date", "forever"); + }else { + jsonObject.put("end_date", idcardEffectEnd); + } + return jsonObject.toString(); + } + + public String coverMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[1]; + } + return null; + } + + public String coverMcc(String mccCode) { + if (StringUtils.isNotEmpty(mccCode)) { + String[] split = mccCode.split("_"); + return split[1]; + } + return null; + } + + /** 支付方式开通(不包含费率信息) **/ + public String coverPayWayInfo() { + JSONArray array = new JSONArray(); + if (StringUtils.isEmpty(this.mccTypeCode) && StringUtils.isEmpty(this.wxMccCode)) { + throw new BizException("商户类别和微信经营类目不能同时为空!"); + } + if (StringUtils.isNotEmpty(this.mccTypeCode)) { + + // 支付宝业务申请信息 + JSONObject aliJson = new JSONObject(); + aliJson.put("pay_way", HM_PAY_WAY_ALIPAY); + aliJson.put("ali_mcc_category_code", coverMcc(this.mccTypeCode)); + array.add(aliJson); + // 银联业务申请信息 + JSONObject unionJson = new JSONObject(); + unionJson.put("pay_way", HM_PAY_WAY_UNION_PAY); + unionJson.put("union_mcc_category_code", coverMcc(this.mccTypeCode)); + array.add(unionJson); + } + + if (StringUtils.isNotEmpty(this.wxMccCode)) { + // 微信业务申请信息 + JSONObject wxJson = new JSONObject(); + wxJson.put("pay_way", HM_PAY_WAY_WEIXIN); + wxJson.put("wechat_category_code", coverMcc(this.wxMccCode)); + array.add(wxJson); + } + return array.toJSONString(); + } + + public void coverOtherPicUrl(String otherPicUrl, JSONArray otherSupplyImgArray) { + if (StringUtils.isNotEmpty(otherPicUrl)) { + JSONObject paramJson = new JSONObject(); + paramJson.put("other_supply_img_url", otherPicUrl); + otherSupplyImgArray.add(paramJson); + } + } + + /** 费率转换 **/ + public JSONObject convertApplymentPayFee() { + JSONObject feeJsonObject = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + feeJsonObject.put("wxRate", convertRate(item.getFeeRate())); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + feeJsonObject.put("aliRate", convertRate(item.getFeeRate())); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 是否配了阶梯费率 + feeJsonObject.put("jtSupport", "yes"); + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 借记卡费率(≤1000元) 单位% + feeJsonObject.put("rate_one_debit", convertRate(item.getLevelList().get(0).getFeeRate())); + // 借记卡费率(>1000元),单位% + feeJsonObject.put("rate_two_debit", convertRate(item.getLevelList().get(1).getFeeRate())); + // 借记卡费率封顶值(>1000元),单位元 + feeJsonObject.put("rate_two_debit_cap", AmountUtil.convertCent2Dollar(item.getMaxFee())); + } + // 贷记卡费率(信用卡) + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 贷记卡费率(≤1000元),单位% + feeJsonObject.put("rate_one_credit", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())); + // 贷记卡费率(>1000元),单位% + feeJsonObject.put("rate_two_credit", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); + } + } + }); + } + return feeJsonObject; + } + + // 0.6 表示0.6% + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return bankChannelNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HnapayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HnapayApplymentInfo.java new file mode 100644 index 0000000..810a7b3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/HnapayApplymentInfo.java @@ -0,0 +1,186 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; + +@Data +public class HnapayApplymentInfo extends ApplymentBasicInfo{ + + /** 客服电话 **/ + public String customerPhone; + + /** 是否为线上商户 0-否 1-是 **/ + public String isLineMch; + + /** 线上产品类型 **/ + public String onlineType; + + /** APP名称/⽹站⽹址/公众号名称 **/ + public String onlineName; + + /** APP下载地址及账号信息 **/ + public String onlineTypeInfo; + + /** 商户协议照 **/ + public String protocolPhoto; + + /** 联行行号 **/ + public String cnapsCode; + + /** 结算账户性质 1-法人 2-非法人 **/ + public String accountNature; + + /** 结算方式 01-T1 02-D1 03-D0 **/ + public String settleWay; + + /** 持卡人手机号 **/ + public String identityPhone; + + /** 结算授权书 **/ + public String settleAuthLetterPhoto; + + /** 结算人手持身份证照 **/ + public String holdIdentityPic; + + /** MCC转换 **/ + public String convertMcc() { + if (this.mccCode.startsWith("0")) { + return this.mccCode.substring(1, this.mccCode.length()); + } + return this.mccCode; + } + + /** 截止日期转换 **/ + public String convertDate(String dateStr) { + if ("长期".equals(dateStr)) { + return "9999-99-99"; + } + return dateStr; + } + + /** 开户银行转换 **/ + public String convertBankId() { + return this.cnapsCode.substring(0, 3); + } + + /** 结算账户类型转换 **/ + public String convertSettType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.settAccountType)) { + // 对公 + return "1"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.settAccountType)) { + // 对私 + return "2"; + } + return ""; + } + + + /** 支付产品 **/ + public JSONArray getFeeConfig() { + JSONArray list = new JSONArray(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + /** 创建各类型配置 默认不开通 **/ + // 银联借记卡 <= 1000 + JSONObject feeJson1 = new JSONObject(); + feeJson1.put("openFlag", "0"); + feeJson1.put("rateTypeId", "0307"); + feeJson1.put("channel", "03"); // 银联二维码 + // 银联借记卡 > 1000 + JSONObject feeJson2 = new JSONObject(); + feeJson2.put("openFlag", "0"); + feeJson2.put("rateTypeId", "0308"); + feeJson2.put("channel", "03"); // 银联二维码 + // 银联刷卡借记卡 + JSONObject feeJson3 = new JSONObject(); + feeJson3.put("openFlag", "0"); + feeJson3.put("rateTypeId", "0401"); + feeJson3.put("channel", "04"); // 银联刷卡 + // 银联刷卡贷记卡 + JSONObject feeJson4 = new JSONObject(); + feeJson4.put("openFlag", "0"); + feeJson4.put("rateTypeId", "0402"); + feeJson4.put("channel", "04"); // 银联刷卡 + // 支付宝 + JSONObject feeJson5 = new JSONObject(); + feeJson5.put("openFlag", "0"); + feeJson5.put("rateTypeId", "0101"); + feeJson5.put("channel", "01"); // 支付宝 + // 微信 + JSONObject feeJson6 = new JSONObject(); + feeJson6.put("openFlag", "0"); + feeJson6.put("rateTypeId", "0201"); + feeJson6.put("channel", "02"); // 微信 + + paywayFeeList.forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 是否开通 + feeJson1.put("openFlag", "1"); + // 借记手续费 + feeJson1.put("feeRate", item.getLevelList().get(0).getFeeRate() + ""); + // 借记封顶 +// feeJson1.put("priceCapped", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + + // 是否开通 + feeJson2.put("openFlag", "1"); + // 借记手续费 + feeJson2.put("feeRate", item.getLevelList().get(1).getFeeRate() + ""); + // 借记封顶 +// feeJson2.put("priceCapped", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + + // 是否开通 +// feeJson4.put("openFlag", "1"); + // 借记手续费 + feeJson4.put("feeRate", item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate() + ""); + // 借记封顶 +// feeJson4.put("priceCapped", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + } + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 是否开通 + feeJson5.put("openFlag", "1"); + // 手续费 + feeJson5.put("feeRate", item.getFeeRate()+""); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 是否开通 + feeJson6.put("openFlag", "1"); + // 手续费 + feeJson6.put("feeRate", item.getFeeRate()+""); + } + }); + list.add(feeJson1); + list.add(feeJson2); + list.add(feeJson3); + list.add(feeJson4); + list.add(feeJson5); + list.add(feeJson6); + } + return list; + } + + @Override + public String bankBranchNo() { + return cnapsCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/IdcardInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/IdcardInfo.java new file mode 100644 index 0000000..d0ead62 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/IdcardInfo.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.jeequan.jeepay.core.annotate.Desensitized; +import com.jeequan.jeepay.core.constants.DesensitizedTypeEnum; +import lombok.Data; + +@Data +public class IdcardInfo { + + /** 身份证姓名 **/ + @Desensitized(type = DesensitizedTypeEnum.CHINESE_NAME) + public String idcardName; + + /** 身份证号 **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + public String idcardNo; + + /** 身份证正面人像面 照片 **/ + public String idcard1Img; + + /** 身份证国徽面 照片 **/ + public String idcard2Img; + + /** 身份证地址 **/ + @Desensitized(type = DesensitizedTypeEnum.ADDRESS) + public String idcardAddress; + + /** 身份证有效期开始时间 **/ + public String idcardEffectBegin; + + /** 身份证有效期截止时间 **/ + public String idcardEffectEnd; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KdbpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KdbpayApplymentInfo.java new file mode 100644 index 0000000..cb00ce6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KdbpayApplymentInfo.java @@ -0,0 +1,188 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.model.params.kdbpay.KdbpayIsvParams; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class KdbpayApplymentInfo extends ApplymentBasicInfo { + /** 商户经营类型 1-现实 2-虚拟 **/ + private String busiLicMain; + /** 商户企业法人电话 **/ + private String idcardPhone; + /** 营业执照类型 01-营业执照 02-营业执照 (多证合一) 03-事业单位法人证书 **/ + private String businessLicenseType; + /** 经营形态 02-普通店 、 01-连锁店 **/ + private String businForm; + /** 注册资本:单位-万元 **/ + public String capital; + /** 行业大类 0-标准、1-优惠、2-减免 **/ + public String standardFlag; + /** 公司规模 1:0-50 人; 2:50-100 人; 3:100 以上 **/ + public String employeeNum; + /** 组织机构代码照 **/ + public String picInstitutional; + /** 协议 **/ + public String agreementImg; + /** 清算授权书 **/ + public String picAuthorization; + /** 银行号 **/ + public String bankNo; + /** 联行号 **/ + public String bankLineNo; + /** 支行名称 **/ + public String bankLineName; + + /** 结算人证据地址 **/ + private String settAccountAdress; + /** 预留电话 **/ + private String accountPhone; + /** 商户客服电话 **/ + private String merHotline; + + /** 预留电话(对公) **/ + private String companyAccountPhone; + /** 银行号(对公) **/ + private String settleBankIdUpTwo; + /** 联行号(对公)**/ + private String openStlnoTwo; + + /** 清算周期 00-T+1 01-D0 02-D+1 **/ + private String settCycle; + + /** 结算类型 渠道侧只支持D0和D1(20231031) **/ + private String settleWay; + + /** 租赁协议(小微使用) **/ + public String leaseAgreement; + + /** + * 账号类型 + * 我方: B:对公,C:对私 + * 渠道所需: 01-对公 02-对私 **/ + public String covertSettAccount() { + if (this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "02"; + } + return settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE) ? "01" : "02"; + } + + /** + * 结算类型(D0,D1) + * 我方: D0,D1, DEF 读取服务商默认配置 + **/ + public String covertSettType(KdbpayIsvParams isvParams) { + if("DEF".equals(this.settleWay)){ + // 读取服务商的配置值 + return StringUtils.defaultString(isvParams.getSettType(), "D1"); + } + // 进件时没选择,默认D1 + return StringUtils.defaultString(this.settleWay, "D1"); + } + + /** + * 清算周期:01-D0 02-D+1 + * (基于结算类型上送结算周期) + **/ + public String covertSettCycle(String settType) { + if ("D0".equals(settType)){ + return "01"; + } + return "02"; + } + + + /** 商户类目 **/ + public String[] covertMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + return this.mccCode.split("_"); + } + return null; + } + + /** 截止日期转换 **/ + public String convertDate(String dateStr) { + if ("长期".equals(dateStr)) { + return "9999.12.31"; + } + return dateStr.replace("-", "."); + } + + /** + * 我方:1-个人, 2-个体工商户, 3-企业, 4-党政、机关及事业单位, 5-其他组织 + * 渠道所需:商户性质 01-企业 02-个体工商户 03-事业单位 04-小微商户 + */ + public String convertMerchantType(){ + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "04"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "02"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "01"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_GOV){ + return "03"; + } + return "04"; + } + + /** 费率信息转换 **/ + public JSONObject convertApplymentPayFee() { + // 费率信息 + JSONObject rateJson = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 清算:移动支付计费比例(%) 保留两位小数,如:0.35 + rateJson.put("jh_rate", convertRate(item.getFeeRate()) + ""); + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 清算:Pos 刷卡-借记卡费率(%)保留两位小数,如:0.35 + rateJson.put("pos_debit_rate", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 清算:Pos 刷卡-借记卡封顶金额 以元为单位 + rateJson.put("pos_debit_limit_max", AmountUtil.convertCent2DollarShort(item.getMaxFee()+"")); + + // 银联:借记卡 借记卡 1000 元以下(含 1000元)以下的费率 + rateJson.put("d_calc_down_val", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 银联:借记卡 1000 元以上扣率 + rateJson.put("d_calc_val", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + } + // 贷记卡费率(信用卡) + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 清算:pos 刷卡-贷记卡费率(%)保留两位小数,如:0.35 + rateJson.put("pos_credit_rate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); + + // 银联:信用卡 1000 元以下(含 1000元)以下的费率 + rateJson.put("c_calc_down_val", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())); + // 银联:信用卡 1000 元以上扣率 + rateJson.put("c_calc_val", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); + } + } + }); + } + return rateJson; + } + + /** 费率转换,单位:% **/ + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return bankLineNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KqpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KqpayApplymentInfo.java new file mode 100644 index 0000000..c3f1130 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/KqpayApplymentInfo.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.core.model.applyment; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class KqpayApplymentInfo extends ApplymentBasicInfo { + + /** 客户经理名称 **/ + private String cusMgrNm; + + /** + * 套餐码 + */ + private String packageCode; + + /** + * 套餐参数信息 + */ + private String packageParameter; + + /** + * 营业执照区域编码 + */ + private String licenseAreaCode; + + /** + * 开户凭证代码 + */ + private String accOpenCode; + + /** + * 开户许可证有效期开始时间 + */ + private String accOpenPeriodBegin; + + /** + * 开户许可证有效期截止时间 + */ + private String accOpenPeriodEnd; + + /** + * 银行预留手机,对私结算必传 + * 非法人对私授权结算时,也用作授权人手机号 + */ + private String bankMobile; + + /** + * 是否是非法人结算,Y:非法人结算;N:法人结算 + */ + private String isUncrpSett; + + /** 法人电话号 **/ + private String legalPersonPhone; + + /** + * 非法人结算授权书 && 个人信息单独授权同意书 + */ + private String personalInformationAttorney; + + /** 授权人手持身份证 */ + private String authHandFssId; + + /** 开户意愿确认函 */ + private String openAccountWillingnessLetter; + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LeshuapayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LeshuapayApplymentInfo.java new file mode 100644 index 0000000..f0b3281 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LeshuapayApplymentInfo.java @@ -0,0 +1,141 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class LeshuapayApplymentInfo extends ApplymentBasicInfo { + + /** 客服电话*/ + private String servicePhone; + + /** 证件类型 */ + private Integer credentialType; + + /** 账户类型 + 1:个人账户 + 2:公司账户*/ + private Integer acctType; + + /** 结算标志*/ + private Integer acctLegalFlag; + + /** 开户支行联行号*/ + private String acctUnionpay; + + /** 开户名 + 法人结算:与法人姓名一致; + 企业账户:与营业执照注册名称一致*/ + private String acctHolder; + + /** 结算人证件 + 个人账户必传,非法人结算只能是身份证,法人结算与法人证件号一致*/ + private String acctIdCardNo; + + /** O 结算人证件类型 + 与法人证件参数相同,默认身份证*/ + private String acctIdCardType; + + /**银行预留号码*/ + private String acctMobile; + + /**非法人结算授权书*/ + private String nonLegSettleAuthPic; + + /**经营场所内设照片*/ + private String insidePic; + + /**商户协议照*/ + private String agreementPic; + + /**商户子类型*/ + private Integer companyChildType; + + /** mcc **/ + public String convertMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[2]; + } + return null; + } + + /** 商户类型 1: 个人 2: 个 3: 企业*/ + public Integer convertMerchantType(){ + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return 1; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return 2; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return 3; + } + return 1; + } + + /** 费率转换 **/ + public JSONObject convertApplymentPayFee() { + JSONObject feeJsonObject = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + feeJsonObject.put("wxRate", convertRate(item.getFeeRate())); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + feeJsonObject.put("aliRate", convertRate(item.getFeeRate())); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 是否配了阶梯费率 + feeJsonObject.put("jtSupport", "yes"); + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // <1000 + feeJsonObject.put("jLittleRate", convertRate(item.getLevelList().get(0).getFeeRate())); + // >1000 + feeJsonObject.put("jBigRate", convertRate(item.getLevelList().get(1).getFeeRate())); + // 借记卡手续费最低值 0.6元 传60,0000 + feeJsonObject.put("jMinCharge", item.getMinFee() == 0 ? 0 : item.getMinFee() + "0000"); + // 借记卡手续费最高值 + feeJsonObject.put("jMaxCharge", item.getMaxFee() == 0 ? 0 : item.getMaxFee() + "0000"); + } + // 贷记卡费率(信用卡) + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // <1000 + feeJsonObject.put("dLittleRate", convertRate(item.getLevelList().get(0).getFeeRate())); + // >1000 + feeJsonObject.put("dBigRate", convertRate(item.getLevelList().get(1).getFeeRate())); + // 贷记卡手续费最低值 + feeJsonObject.put("dMinCharge", item.getMinFee() == 0 ? 0 : item.getMinFee() + "0000"); + // 贷记卡手续费最高值 + feeJsonObject.put("dMaxCharge", item.getMaxFee() == 0 ? 0 : item.getMaxFee() + "0000"); + } + } + }); + } + return feeJsonObject; + } + + // 60 表示0.6% + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(10000)).setScale(0, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return acctUnionpay; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklpayApplymentInfo.java new file mode 100644 index 0000000..62b20e9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklpayApplymentInfo.java @@ -0,0 +1,196 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@Data +public class LklpayApplymentInfo extends ApplymentBasicInfo { + + private String merRegName; + + /** 进件POS类型 **/ + private String posType; + + /** 商户经营内容 **/ + private String merBusiContent; + + /** 其他附件 **/ + private String otherFile; + + /** 协议照片 **/ + private String agreementImg; + + /** 电子合同编号 **/ + private String contractNo; + + /** 结算账户开户行行号 **/ + private String openningBankCode; + + /** 结算账户开户行名称 **/ + private String openningBankName; + + /** 结算账户清算行号 **/ + private String clearingBankCode; + + /** + * 开户银行地区码 + */ + private JSONArray settleAreaCode; + + /** + * 开户银行地区 + */ + private JSONArray settleAreaName; + + + /** + * @author: xiaoyu + * @date: 2022/4/19 10:41 + * @describe: 结算账户类型 + */ + public String getSettAccType() { + if ("B".equalsIgnoreCase(this.settAccountType)) { // 对公 + return "57"; + }else if ("C".equalsIgnoreCase(this.settAccountType)) { // 对私 + return "58"; + } + return ""; + } + + /** + * @author: xiaoyu + * @date: 2022/4/21 17:58 + * @describe: + */ + public String coverMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[1]; + } + return null; + } + + /** + * @author: xiaoyu + * @date: 2022/4/21 17:58 + * @describe: 有效期截止日期返回值 + */ + public String convertDateEnd(String dateEndStr){ + if ("长期".equals(dateEndStr)) { + return "9999-12-31"; + }else { + return dateEndStr; + } + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public JSONArray convertPaywayFeeList(){ + + if(this.paywayFeeList == null){ + return null; + } + + JSONArray result = new JSONArray(); + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 阶梯费率 + if ((paywayFee.getWayCode().startsWith("YSF_") || paywayFee.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType())) { + // 借记卡费率 + if(CollUtil.isNotEmpty(paywayFee.getLevelList())){ + JSONObject params1 = new JSONObject(); + // 费率类型 + params1.put("feeRateTypeCode", "300"); + // 类型名称 + params1.put("feeRateTypeName", "银联借记卡"); + // 手续费率 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + params1.put("feeRatePct", convertRate(paywayFee.getLevelList().get(0).getFeeRate()) + ""); + // 借记封顶 +// params1.put("feeUpperAmtPcnt", AmountUtil.convertCent2Dollar(paywayFee.getMaxFee())); + // 单笔保底 +// params1.put("feeLowerAmtPcnt", AmountUtil.convertCent2Dollar(paywayFee.getMinFee())); + result.add(params1); + + JSONObject params2 = new JSONObject(); + // 费率类型 + params2.put("feeRateTypeCode", "314"); + // 类型名称 + params2.put("feeRateTypeName", "银联二维码借记卡"); + // 手续费率 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + params2.put("feeRatePct", convertRate(paywayFee.getLevelList().get(0).getFeeRate()) + ""); + // 借记封顶 +// params2.put("feeUpperAmtPcnt", AmountUtil.convertCent2Dollar(paywayFee.getMaxFee())); + // 单笔保底 +// params2.put("feeLowerAmtPcnt", AmountUtil.convertCent2Dollar(paywayFee.getMinFee())); + result.add(params2); + } + + // 贷记卡费率 + if(paywayFee.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(paywayFee.getCreditCardPaywayFee().getLevelList())){ + + JSONObject params1 = new JSONObject(); + params1.put("feeRateTypeCode", "301"); + params1.put("feeRateTypeName", "银联贷记卡"); + params1.put("feeRatePct", convertRate(paywayFee.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + result.add(params1); + + JSONObject params2 = new JSONObject(); + params2.put("feeRateTypeCode", "315"); + params2.put("feeRateTypeName", "银联二维码贷记卡"); + params2.put("feeRatePct", convertRate(paywayFee.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + result.add(params2); + } + } + + JSONObject json = new JSONObject(); + // 第一步: 转换产品ID ( 本系统 --》 拉卡拉 ) + String bizProductCode = null; + switch (paywayFee.getWayCode()){ + case CS.PAY_WAY_CODE.WX_BAR: bizProductCode = "307"; break; + case CS.PAY_WAY_CODE.WX_JSAPI: bizProductCode = "302"; break; + case CS.PAY_WAY_CODE.WX_H5: bizProductCode = "302"; break; + case CS.PAY_WAY_CODE.WX_LITE: bizProductCode = "302"; break; + case CS.PAY_WAY_CODE.WX_NATIVE: bizProductCode = "302"; break; + case CS.PAY_WAY_CODE.ALI_BAR: bizProductCode = "308"; break; + case CS.PAY_WAY_CODE.ALI_JSAPI: bizProductCode = "303"; break; + case CS.PAY_WAY_CODE.ALI_LITE: bizProductCode = "303"; break; + case CS.PAY_WAY_CODE.ALI_PC: bizProductCode = "303"; break; + case CS.PAY_WAY_CODE.ALI_QR: bizProductCode = "303"; break; + case CS.PAY_WAY_CODE.ALI_WAP: bizProductCode = "303"; break; + } + + // 拉卡拉不存在该产品 + if(StringUtils.isEmpty(bizProductCode)){ + continue; + } + + // 费率类型 + json.put("feeRateTypeCode", bizProductCode); + // 费率类型名称 + json.put("feeRateTypeName", paywayFee.getWayCode()); + + // 单笔费率 + if(PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())){ + json.put("feeRatePct", convertRate(paywayFee.getFeeRate())); + result.add(json); + } + } + return result; + + } + + public static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + @Override + public String bankBranchNo() { + return openningBankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/Lklsb2bpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/Lklsb2bpayApplymentInfo.java new file mode 100644 index 0000000..4a8626c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/Lklsb2bpayApplymentInfo.java @@ -0,0 +1,297 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +@Data +public class Lklsb2bpayApplymentInfo extends ApplymentBasicInfo { + + /** + * 商户注册名称 + **/ + private String merRegName; + + /** + * 是否为法人 + **/ + private String isLegalInfo; + + /** + * 商户经营内容 + **/ + private String licenseBusiness; + + /** + * 银行省市县编码 (包含省市县三级编码) + **/ + private JSONArray mchAreaCode; + + /** + * 经度 + **/ + private String latitude; + + /** + * 纬度 + **/ + private String longtude; + + /** + * 银行查询地区类型 + **/ + private String selectAreaCode; + + /** + * 联行行号 + **/ + private String openningBankCode; + + /** + * 清算行号 + **/ + private String clearingBankCode; + + /** + * 其他附件 + **/ + private String otherFile; + + /** + * 协议照片 + **/ + private String agreeMentImg; + + /** + * 开户许可证照片, + **/ + private String openingPermitImg; + + public String getCompanyAccountLicenseImg() { + return openingPermitImg; + } + + /** + * 法人授权函照片 + **/ + private String letterOfAuthorizationImg; + + /** + * 结算方式 D0、D1 + **/ + private String settleType; + + + /** + * 结算账户类型 + **/ + @JSONField(serialize = false) + public String getSettAccType() { + if ("B".equalsIgnoreCase(this.settAccountType)) { // 对公 + return "57"; + } else if ("C".equalsIgnoreCase(this.settAccountType)) { // 对私 + return "58"; + } + return ""; + } + + /** + * MCC + **/ + private String coverMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[1]; + } + return null; + } + + /** + * 商户类型 + **/ + private String coverMerType() { + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType) { + return "TP_PERSONAL"; + } else if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == this.merchantType) { + return "TP_MERCHANT"; + } + return ""; + } + + /** + * 日期转换 + **/ + private String convertDateEnd(String dateEndStr) { + if ("长期".equals(dateEndStr)) { + return "9999-12-31"; + } else { + return dateEndStr; + } + } + + /** + * 类型转换:标准格式 ---》 接口自定义格式 + **/ + private Map convertPaywayFeeList() { + + if (this.paywayFeeList == null) { + return null; + } + + boolean wxConfig = false; + boolean aliConfig = false; + boolean upConfig = false; + + JSONArray result = new JSONArray(); + Map mapResult = new HashMap<>(); + for (PaywayFee paywayFee : this.paywayFeeList) { + + if ((paywayFee.getWayCode().startsWith("UP_") || paywayFee.getWayCode().startsWith("YSF_"))) { + + // 阶梯费率 + if (PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType())) { + if (upConfig) continue; + + // 借记卡费率 + if (CollUtil.isNotEmpty(paywayFee.getLevelList())) { + paywayFee.getLevelList().forEach(item -> { + String feeValue = convertRate(item.getFeeRate()); + if (item.getMaxFee() == 100000L) { + // 借记卡 < 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YSF_DISCOUNT_DEBIT_FEE"); + mapResult.put("YSF_DISCOUNT_DEBIT_FEE", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YL_DISCOUNT_DEBIT_FEE"); + mapResult.put("YL_DISCOUNT_DEBIT_FEE", rateItem); + } else { + // 借记卡 >= 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "DEBIT_CARD"); + rateItem.put("topFee", "20d"); + mapResult.put("DEBIT_CARD", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "UNIONPAY_WALLET_DEBIT_FEE"); + rateItem.put("topFee", "20d"); + mapResult.put("UNIONPAY_WALLET_DEBIT_FEE", rateItem); + } + }); + } + + if (paywayFee.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(paywayFee.getCreditCardPaywayFee().getLevelList())) { + paywayFee.getCreditCardPaywayFee().getLevelList().forEach(item -> { + String feeValue = convertRate(item.getFeeRate()); + if (item.getMaxFee() == 100000L) { + // 贷记卡 < 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YSF_DISCOUNT_DEBIT_FEE"); + mapResult.put("YSF_DISCOUNT_CREDIT_FEE", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YL_DISCOUNT_CREDIT_FEE"); + mapResult.put("YL_DISCOUNT_CREDIT_FEE", rateItem); + } else { + // 贷记卡 >= 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "DEBIT_CARD"); + rateItem.put("topFee", "20d"); + mapResult.put("DEBIT_CARD", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "UNIONPAY_WALLET_CREDIT_FEE"); + rateItem.put("topFee", "20d"); + mapResult.put("UNIONPAY_WALLET_CREDIT_FEE", rateItem); + } + }); + } + + upConfig = true; + + } + + } + + if ((paywayFee.getWayCode().startsWith("WX_"))) { + if (wxConfig) continue; + + JSONObject json1 = new JSONObject(); + // 微信费率 + json1.put("feeCode", "WECHAT"); + json1.put("feeValue", convertRate(paywayFee.getFeeRate())); + mapResult.put("WECHAT", json1); + +// JSONObject json2 = new JSONObject(); +// // 微信线上费率 +// json2.put("feeCode", "LINE_WECHAT"); +// json2.put("feeValue", convertRate(paywayFee.getFeeRate())); +// result.add(json2); + + wxConfig = true; + } + + if ((paywayFee.getWayCode().startsWith("ALI_"))) { + if (aliConfig) continue; + + JSONObject json1 = new JSONObject(); + // 支付宝费率 + json1.put("feeCode", "ALIPAY"); + json1.put("feeValue", convertRate(paywayFee.getFeeRate())); + mapResult.put("ALIPAY", json1); + + aliConfig = true; + } + + if (CS.PAY_WAY_CODE.D0.equals(paywayFee.getWayCode())) { + String feeRate = convertRate(paywayFee.getFeeRate()); + // TODO 特殊支付费率 暂固定 + JSONObject scanPaySecond = new JSONObject(); + // 扫码d0费率 + scanPaySecond.put("feeCode", "SCAN_PAY_SECOND"); + scanPaySecond.put("feeValue", feeRate); + mapResult.put("SCAN_PAY_SECOND", scanPaySecond); + + JSONObject cardSecond = new JSONObject(); + // 刷卡D0费率 + cardSecond.put("feeCode", "CARD_SECOND"); + cardSecond.put("feeValue", feeRate); + mapResult.put("CARD_SECOND", cardSecond); + } + } + + return mapResult; + + } + + private static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return openningBankCode; + } + + @Override + public String bankAccountName() { + return super.bankAccountName(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklspayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklspayApplymentInfo.java new file mode 100644 index 0000000..21ef036 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/LklspayApplymentInfo.java @@ -0,0 +1,297 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +@Data +public class LklspayApplymentInfo extends ApplymentBasicInfo { + + /** + * 商户注册名称 + **/ + private String merRegName; + + /** + * 是否为法人 + **/ + private String isLegalInfo; + + /** + * 商户经营内容 + **/ + private String licenseBusiness; + + /** + * 银行省市县编码 (包含省市县三级编码) + **/ + private JSONArray mchAreaCode; + + /** + * 经度 + **/ + private String latitude; + + /** + * 纬度 + **/ + private String longtude; + + /** + * 银行查询地区类型 + **/ + private String selectAreaCode; + + /** + * 联行行号 + **/ + private String openningBankCode; + + /** + * 清算行号 + **/ + private String clearingBankCode; + + /** + * 其他附件 + **/ + private String otherFile; + + /** + * 协议照片 + **/ + private String agreeMentImg; + + /** + * 开户许可证照片, + **/ + private String openingPermitImg; + + public String getCompanyAccountLicenseImg() { + return openingPermitImg; + } + + /** + * 法人授权函照片 + **/ + private String letterOfAuthorizationImg; + + /** + * 结算方式 D0、D1 + **/ + private String settleType; + + + /** + * 结算账户类型 + **/ + @JSONField(serialize = false) + public String getSettAccType() { + if ("B".equalsIgnoreCase(this.settAccountType)) { // 对公 + return "57"; + } else if ("C".equalsIgnoreCase(this.settAccountType)) { // 对私 + return "58"; + } + return ""; + } + + /** + * MCC + **/ + private String coverMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] split = this.mccCode.split("_"); + return split[1]; + } + return null; + } + + /** + * 商户类型 + **/ + private String coverMerType() { + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType) { + return "TP_PERSONAL"; + } else if (MchApplyment.MERCHANT_TYPE_ENTERPRISE == this.merchantType) { + return "TP_MERCHANT"; + } + return ""; + } + + /** + * 日期转换 + **/ + private String convertDateEnd(String dateEndStr) { + if ("长期".equals(dateEndStr)) { + return "9999-12-31"; + } else { + return dateEndStr; + } + } + + /** + * 类型转换:标准格式 ---》 接口自定义格式 + **/ + private Map convertPaywayFeeList() { + + if (this.paywayFeeList == null) { + return null; + } + + boolean wxConfig = false; + boolean aliConfig = false; + boolean upConfig = false; + + JSONArray result = new JSONArray(); + Map mapResult = new HashMap<>(); + for (PaywayFee paywayFee : this.paywayFeeList) { + + if ((paywayFee.getWayCode().startsWith("UP_") || paywayFee.getWayCode().startsWith("YSF_"))) { + + // 阶梯费率 + if (PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType())) { + if (upConfig) continue; + + // 借记卡费率 + if (CollUtil.isNotEmpty(paywayFee.getLevelList())) { + paywayFee.getLevelList().forEach(item -> { + String feeValue = convertRate(item.getFeeRate()); + if (item.getMaxFee() == 100000L) { + // 借记卡 < 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YSF_DISCOUNT_DEBIT_FEE"); + mapResult.put("YSF_DISCOUNT_DEBIT_FEE", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YL_DISCOUNT_DEBIT_FEE"); + mapResult.put("YL_DISCOUNT_DEBIT_FEE", rateItem); + } else { + // 借记卡 >= 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "DEBIT_CARD"); + rateItem.put("topFee", "20d"); + mapResult.put("DEBIT_CARD", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "UNIONPAY_WALLET_DEBIT_FEE"); + rateItem.put("topFee", "20d"); + mapResult.put("UNIONPAY_WALLET_DEBIT_FEE", rateItem); + } + }); + } + + if (paywayFee.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(paywayFee.getCreditCardPaywayFee().getLevelList())) { + paywayFee.getCreditCardPaywayFee().getLevelList().forEach(item -> { + String feeValue = convertRate(item.getFeeRate()); + if (item.getMaxFee() == 100000L) { + // 贷记卡 < 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YSF_DISCOUNT_DEBIT_FEE"); + mapResult.put("YSF_DISCOUNT_CREDIT_FEE", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "YL_DISCOUNT_CREDIT_FEE"); + mapResult.put("YL_DISCOUNT_CREDIT_FEE", rateItem); + } else { + // 贷记卡 >= 1000 + JSONObject rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "DEBIT_CARD"); + rateItem.put("topFee", "20d"); + mapResult.put("DEBIT_CARD", rateItem); + + rateItem = new JSONObject(); + rateItem.put("feeValue", feeValue); + rateItem.put("feeCode", "UNIONPAY_WALLET_CREDIT_FEE"); + rateItem.put("topFee", "20d"); + mapResult.put("UNIONPAY_WALLET_CREDIT_FEE", rateItem); + } + }); + } + + upConfig = true; + + } + + } + + if ((paywayFee.getWayCode().startsWith("WX_"))) { + if (wxConfig) continue; + + JSONObject json1 = new JSONObject(); + // 微信费率 + json1.put("feeCode", "WECHAT"); + json1.put("feeValue", convertRate(paywayFee.getFeeRate())); + mapResult.put("WECHAT", json1); + +// JSONObject json2 = new JSONObject(); +// // 微信线上费率 +// json2.put("feeCode", "LINE_WECHAT"); +// json2.put("feeValue", convertRate(paywayFee.getFeeRate())); +// result.add(json2); + + wxConfig = true; + } + + if ((paywayFee.getWayCode().startsWith("ALI_"))) { + if (aliConfig) continue; + + JSONObject json1 = new JSONObject(); + // 支付宝费率 + json1.put("feeCode", "ALIPAY"); + json1.put("feeValue", convertRate(paywayFee.getFeeRate())); + mapResult.put("ALIPAY", json1); + + aliConfig = true; + } + + if (CS.PAY_WAY_CODE.D0.equals(paywayFee.getWayCode())) { + String feeRate = convertRate(paywayFee.getFeeRate()); + // TODO 特殊支付费率 暂固定 + JSONObject scanPaySecond = new JSONObject(); + // 扫码d0费率 + scanPaySecond.put("feeCode", "SCAN_PAY_SECOND"); + scanPaySecond.put("feeValue", feeRate); + mapResult.put("SCAN_PAY_SECOND", scanPaySecond); + + JSONObject cardSecond = new JSONObject(); + // 刷卡D0费率 + cardSecond.put("feeCode", "CARD_SECOND"); + cardSecond.put("feeValue", feeRate); + mapResult.put("CARD_SECOND", cardSecond); + } + } + + return mapResult; + + } + + private static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return openningBankCode; + } + + @Override + public String bankAccountName() { + return super.bankAccountName(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/MchModifyApplymentModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/MchModifyApplymentModel.java new file mode 100644 index 0000000..4210a18 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/MchModifyApplymentModel.java @@ -0,0 +1,161 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.alibaba.fastjson.JSONArray; +import com.jeequan.jeepay.core.annotate.Desensitized; +import com.jeequan.jeepay.core.constants.DesensitizedTypeEnum; +import lombok.Data; + +import java.io.Serializable; + +/** + * 商户进件变更信息模型 + * @since 2023-12-06 17:00:22 + */ +@Data +public class MchModifyApplymentModel implements Serializable { + + /** + * 变更流水号 + */ + private String modifyApplyId; + + + private String mchApplyId; + + /** + * 1、基本资料变更; 2、结算信息变更; 3、费率信息变更; + */ + private Byte modifyApplyType; + + private String mchShortName; + + + /*=========结算信息变更========*/ + + /** + * 结算账号类型 B:对公,C:对私 + */ + private String settAccountType; + + /** + * 是否是非法人结算,Y: 是; N: 不是 + */ + private String illegal; + + /** + * 结算账号名称 + **/ + @Desensitized(type = DesensitizedTypeEnum.CHINESE_NAME) + private String settAccountName; + + /** + * 结算银行卡账号 + **/ + @Desensitized(type = DesensitizedTypeEnum.BANK_CARD) + private String settAccountNo; + + /** + * 结算银行名称 + **/ + private String settAccountBankName; + + /** + * 银行卡图片/开户许可证件 + */ + private String settAccountLicenseImg; + + /** + * 银行卡反面图片 + */ + private String settBankCardBackImg; + + /** + * 结算银行开户支行区域编码 + **/ + private JSONArray settAccountBankBranchAreaCode; + + /** + * 结算银行开户支行区域名称 + */ + private JSONArray settAccountBankBranchAreaName; + + /** + * 支行名称 + */ + private String settAccountBankBranchName; + + /** + * 支行联行号 + */ + private String bankSubCode; + + /** + * 结算账户预留手机号 + */ + private String phone; + + /** + * 银行行号 + */ + private String bankCode; + + /** + * 非法人结算授权函 + */ + private String nonLegSettleAuthPic; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证号 + **/ + @Desensitized(type = DesensitizedTypeEnum.ID_CARD) + private String settAccountIdcardNo; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证正面人像面 照片 + **/ + private String settAccountIdcard1Img; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证国徽面 照片 + **/ + private String settAccountIdcard2Img; + + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证有效期开始时间 + **/ + private String settAccountIdcardEffectBegin; + + /** + * (结算到非法人时必填) 结算卡持卡人 身份证有效期截止时间 + **/ + private String settAccountIdcardEffectEnd; + + /** + * 信息变更表,不同通道需求不一致 + */ + private String changeFormPic; + + /** + * 结算类型 + */ + private String settlementType; + + /** + * 开户凭证图片,部分通道 (快钱) 需要 + */ + private String accOpenCertImg; + + /** + * 授权人手持身份证 + */ + private String authHandImg; + + /** + * 支付宝账号, 手机号 + */ + private String alipayLogonId; + + /** 默认结算类型:bankCard-结算到银行卡 alipayAccount-结算到支付宝账号 **/ + private String defaultSettleType; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/PaywayFee.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/PaywayFee.java new file mode 100644 index 0000000..7c17690 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/PaywayFee.java @@ -0,0 +1,482 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.MutableTriple; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; + +/** + * 支付方式的产品费率定义 + * + * @author terrfly + * @date 2022/1/6 17:04 + */ +@Data +@Slf4j +public class PaywayFee implements Comparable { + + /** + * 单笔固定 、 单笔费率、 单笔阶梯 + **/ + public static final String FEE_TYPE_FIX = "FIX"; + public static final String FEE_TYPE_SINGLE = "SINGLE"; + public static final String FEE_TYPE_LEVEL = "LEVEL"; + public static final String FEE_TYPE_FIXANDRATE = "FIXANDRATE"; // 单笔 + 费率( 目前 仅服务商提现使用该模式 ) + public static final String FEE_TYPE_TRANSMODE = "TRANSMODE"; // 转账模式: 单笔 + 费率( 并且可配置最大和保底费用 ) + + /** + * 状态 0-关闭 1-开启 + **/ + private Byte state; + + /** + * 支付方式代码 + */ + private String wayCode; + + /** + * 进件是否显示(仅渠道商配置) + */ + private Byte applymentSupport; + + /** + * 是否可编辑(仅渠道商配置) + */ + private Byte editable; + + /** + * 费率方式 + */ + private String feeType; + + /** + * 免收手续费额度 单位: 分 + */ + private Long freeLimit; + + /** + * 固定费用, 仅FIX生效 单位: 分 + */ + private Long fixFee; + + /** + * 费率(存储的为实际费率值, 如费率为: 0.6% 则存储值为: 0.006) + */ + private BigDecimal feeRate; + + /** + * 费率计算最低收取值 / 阶梯价格1 单位: 分 + */ + private Long minFee; + + /** + * 费率计算最高收取值 / 阶梯价格2 单位: 分 + */ + private Long maxFee; + + /** + * 阶梯定价列表 + **/ + List levelList; + + /** + * 主model里保存的是: 借记卡(储蓄卡)的费率设置值 + * creditCardPaywayFee: 贷记卡(信用卡)的费率设置值 + **/ + private PaywayFee creditCardPaywayFee; + + /** + * 计算费率值 + **/ + public Long calFee(Long orderAmount) { + return this.calFeeAndSnapshot(orderAmount).right; + } + + /** + * 转换为: MutableTriple<手续费快照, 商户实际手续费, 本次退还手续费> + **/ + public static MutableTriple convert2MutableTriple(MutablePair mutablePair, Long oldMchFee) { + return MutableTriple.of(mutablePair.getLeft(), mutablePair.getRight(), AmountUtil.minZero(oldMchFee - mutablePair.getRight())); + } + + + /** + * 计算金额的费率费用 和 快照字符串 + **/ + public MutablePair calFeeAndSnapshot(Long orderAmount) { + + // 单笔费率 + if (FEE_TYPE_SINGLE.equals(this.feeType)) { + String str = String.format("%s单笔费率:%s", genFreeLimitStr(), AmountUtil.convertPercentage(feeRate, 4)); + return MutablePair.of(str, calFreeLimitAmount(orderAmount, AmountUtil.calPercentageFee(orderAmount, feeRate))); + } + + // 单笔固定 + if (FEE_TYPE_FIX.equals(this.feeType)) { + String str = String.format("%s单笔固定:%s元", genFreeLimitStr(), AmountUtil.convertCent2Dollar(this.fixFee)); + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.fixFee)); + } + + // 单笔固定 + 费率 + if (FEE_TYPE_FIXANDRATE.equals(this.feeType)) { + String str = String.format("%s[%s元 + %s]", genFreeLimitStr(), AmountUtil.convertCent2Dollar(this.fixFee), AmountUtil.convertPercentage(feeRate, 4)); + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.fixFee + AmountUtil.calPercentageFee(orderAmount, feeRate))); + } + + // 转账模式 + if (FEE_TYPE_TRANSMODE.equals(this.feeType)) { + String str = String.format("单笔[%s元 + %s], 保底%s元, 封顶%s元", + AmountUtil.convertCent2Dollar(this.fixFee), AmountUtil.convertPercentage(feeRate, 4), + AmountUtil.convertCent2Dollar(this.getMinFee()), AmountUtil.convertCent2Dollar(this.getMaxFee()) + ); + + Long fee = calFreeLimitAmount(orderAmount, this.fixFee + AmountUtil.calPercentageFee(orderAmount, feeRate)); + + // 费用超过 最大费率 + if (this.maxFee != null && fee > this.maxFee) { + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.maxFee)); + } + + // 费用小于 保底费率 + if (this.minFee != null && fee < this.minFee) { + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.minFee)); + } + + return MutablePair.of(str, fee); + } + + // 阶梯费率 + // 0 - 100 区间值: ( ] 左侧大于, 右侧小于等于。 + // 100 - 200 + + for (PaywayFee paywayFeeItem : levelList) { + + // ( ] 左侧大于, 右侧小于等于。 + if (paywayFeeItem.getMinFee() < orderAmount && orderAmount <= paywayFeeItem.getMaxFee()) { + + Long fee = AmountUtil.calPercentageFee(orderAmount, paywayFeeItem.getFeeRate()); + + String str = String.format("%s(%s元-%s元]阶梯费率: %s, 保底%s元, 封顶%s元", + genFreeLimitStr(), + AmountUtil.convertCent2Dollar(paywayFeeItem.getMinFee()), + AmountUtil.convertCent2Dollar(paywayFeeItem.getMaxFee()), + AmountUtil.convertPercentage(paywayFeeItem.getFeeRate(), 4), + AmountUtil.convertCent2Dollar(this.getMinFee()), + AmountUtil.convertCent2Dollar(this.getMaxFee()) + ); + + + // 费用超过 最大费率 + if (this.maxFee != null && fee > this.maxFee) { + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.maxFee)); + } + + // 费用小于 保底费率 + if (this.minFee != null && fee < this.minFee) { + return MutablePair.of(str, calFreeLimitAmount(orderAmount, this.minFee)); + } + + return MutablePair.of(str, calFreeLimitAmount(orderAmount, fee)); + } + + } + + // 无费用 + return MutablePair.of("未匹配到费率阶梯", 0L); + } + + + /** + * 按照阶梯费率 排序 + **/ + @Override + public int compareTo(PaywayFee o) { + return this.minFee.compareTo(o.minFee); + } + + + /** + * 比较两个费率的配置 是否满足 传入的 预期值 expect: + * 单笔比较费率, 阶梯比较每个阶梯的费率值和最大、 最小收费。 + * 如配置错误, 或比较不正确, 直接抛异常。 + * 0 : 相等 + * 1: 当前 > 传入 + * -1: 当前 < 传入 + * 10: 当前 >= 传入 + * -10: 当前 <= 传入 + **/ + + public void compareByFee(PaywayFee compareFee, int expect, String infoName) { + + // 费率方式不同 + if (!Objects.equals(this.feeType, compareFee.getFeeType())) { + return; +// throw new BizException(String.format("[%s]的费率计算方式与[%s]的配置不一致", this.wayCode, infoName)); + } + + // 单笔费率 + if (PaywayFee.FEE_TYPE_SINGLE.equals(this.feeType)) { + + // 比较费率值即可 + int result = this.feeRate.compareTo(compareFee.getFeeRate()); + + if (judgeResult(expect, result)) { // 不满足规则 + throw new BizException(String.format("[%s]设置费率{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertPercentage(this.feeRate, 4), expect2Str(expect), infoName, AmountUtil.convertPercentage(compareFee.feeRate, 4))); + } + + // 满足条件 + return; + } + + // 转账模式费率 + if (PaywayFee.FEE_TYPE_TRANSMODE.equals(this.feeType)) { + + // 判断 固定金额 + if (judgeResult(expect, this.fixFee.compareTo(compareFee.fixFee))) { + throw new BizException(String.format("[%s]设置费率固定费用{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertCent2Dollar(this.fixFee), expect2Str(expect), infoName, AmountUtil.convertCent2Dollar(compareFee.fixFee))); + } + + int result = this.feeRate.compareTo(compareFee.getFeeRate()); + + if (judgeResult(expect, result)) { // 不满足规则 + throw new BizException(String.format("[%s]设置费率{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertPercentage(this.feeRate, 4), expect2Str(expect), infoName, AmountUtil.convertPercentage(compareFee.feeRate, 4))); + } + + // 判断 最大值 + if (judgeResult(expect, this.maxFee.compareTo(compareFee.maxFee))) { + throw new BizException(String.format("[%s]设置封顶费用{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertCent2Dollar(this.maxFee), expect2Str(expect), infoName, AmountUtil.convertCent2Dollar(compareFee.maxFee))); + } + + // 判断 最小值 + if (judgeResult(expect, this.minFee.compareTo(compareFee.minFee))) { + throw new BizException(String.format("[%s]设置保底费用{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertCent2Dollar(this.minFee), expect2Str(expect), infoName, AmountUtil.convertCent2Dollar(compareFee.minFee))); + } + + // 满足条件 + return; + } + + // 以下为: 阶梯费率 + + // 两侧 数量不一致 + if (CollUtil.size(this.levelList) != CollUtil.size(compareFee.getLevelList())) { + throw new BizException(String.format("[%s]的阶梯费率数量与[%s]的配置数量不一致", this.wayCode, infoName)); + } + + // 判断 最大值 + if (judgeResult(expect, this.maxFee.compareTo(compareFee.maxFee))) { + throw new BizException(String.format("[%s]设置封顶费用{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertCent2Dollar(this.maxFee), expect2Str(expect), infoName, AmountUtil.convertCent2Dollar(compareFee.maxFee))); + } + + // 判断 最小值 + if (judgeResult(expect, this.minFee.compareTo(compareFee.minFee))) { + throw new BizException(String.format("[%s]设置保底费用{%s} 需要【%s】【%s】的当前配置值:{%s}", + this.wayCode, AmountUtil.convertCent2Dollar(this.minFee), expect2Str(expect), infoName, AmountUtil.convertCent2Dollar(compareFee.minFee))); + } + + // 阶梯费率 全部为空的 + if (CollUtil.isEmpty(this.levelList)) { + return; + } + + // 对比阶梯费率 + checkList(this.levelList, compareFee.levelList, expect, wayCode, infoName); + + // 比较贷记卡费率 + boolean isUnequals = this.creditCardPaywayFee == null ^ compareFee.creditCardPaywayFee == null; + if (isUnequals) { + throw new BizException(String.format("[%s]银联模式和[%s]的配置不一致", this.wayCode, infoName)); + } + + if (this.creditCardPaywayFee != null) { + this.creditCardPaywayFee.setWayCode(this.getWayCode()); + this.creditCardPaywayFee.compareByFee(compareFee.creditCardPaywayFee, expect, infoName); + } + } + + /** + * 比较阶梯费率 + */ + public static void checkList(List srcList, List compareFeeList, int expect, + String wayCode, String infoName) { + // 按照阶梯排序 + Collections.sort(srcList); + Collections.sort(compareFeeList); + + log.info("====校验阶梯费率"); + for (int i = 0; i < srcList.size(); i++) { + PaywayFee c1 = srcList.get(i); + PaywayFee c2 = compareFeeList.get(i); + + // 阶梯费率的阶梯金额不一致 + if (c1.minFee.longValue() != c2.minFee.longValue()) { + throw new BizException(String.format("[%s]的第[%s]阶梯起始金额与[%s]的配置不一致", wayCode, (i + 1), infoName)); + } + + // 阶梯费率的阶梯金额不一致 + if (c1.maxFee.longValue() != c2.maxFee.longValue()) { + throw new BizException(String.format("[%s]的第[%s]阶梯结束金额与[%s]的配置不一致", wayCode, (i + 1), infoName)); + } + + // 判断阶梯费率 + if (judgeResult(expect, c1.feeRate.compareTo(c2.feeRate))) { + throw new BizException(String.format("[%s]的第[%s]阶梯设置费率{%s} 需要【%s】【%s】的阶梯配置值:{%s}", + wayCode, (i + 1), AmountUtil.convertPercentage(c1.feeRate, 4), expect2Str(expect), infoName, AmountUtil.convertPercentage(c2.feeRate, 4))); + } + } + } + + /** + * 判断预期是否满足 + */ + private static boolean judgeResult(int expect, int result) { + + // 相等 + if (expect == result) { + return false; + } + + // 或者相等 + if (expect == -10 && result <= 0) { + return false; + } + + // 或者相等 + if (expect == 10 && result >= 0) { + return false; + } + + // 不满足 + return true; + } + + private static String expect2Str(int expect) { + + if (expect == 0) { + return "等于"; + } else if (expect == 1) { + return "大于"; + } else if (expect == -1) { + return "小于"; + } else if (expect == 10) { + return "大于等于"; + } else if (expect == -10) { + return "小于等于"; + } + + return null; + } + + + /** + * 获取免费字符串 + **/ + private String genFreeLimitStr() { + + if (this.freeLimit == null) { + return ""; + } + + return AmountUtil.convertCent2Dollar(this.freeLimit) + "元内免手续费, "; + } + + /** + * 获取是否免费 + **/ + private Long calFreeLimitAmount(Long orderAmount, Long fee) { + + if (this.freeLimit == null) { + return fee; + } + + if (orderAmount <= this.freeLimit) { + return 0L; + } + return fee; + } + + public static PaywayFee toEmptyData(PaywayFee paywayFee) { + paywayFee.setFeeRate(null); + Optional.ofNullable(paywayFee.getLevelList()).ifPresent(r -> { + for (PaywayFee fee : r) { + fee.setFeeRate(null); + } + }); + + Optional.ofNullable(paywayFee.getCreditCardPaywayFee()).map(PaywayFee::getLevelList) + .ifPresent(r -> { + for (PaywayFee fee : r) { + fee.setFeeRate(null); + } + } + ); + + return paywayFee; + } + + /** + * 费率 + * @param self 目标费率 + * @param parentModel 父级模板费率 + */ + public static void resetData(Map self, Map parentModel) { + if (CollUtil.isEmpty(parentModel)) { + return; + } + + for (Map.Entry parentDefRateItem : parentModel.entrySet()) { + String wayCode = parentDefRateItem.getKey(); + PaywayFee item = parentDefRateItem.getValue(); + + Optional.of(self).ifPresent(r -> { + PaywayFee paywayFee = r.get(wayCode); + if (paywayFee == null) { + PaywayFee emptyData = PaywayFee.toEmptyData(item); + emptyData.setState(item.getState()); + emptyData.setApplymentSupport(item.getApplymentSupport()); + r.put(wayCode, emptyData); + } else { + if (!Objects.equals(paywayFee.getFeeType(), item.getFeeType())) { + // 费率模式不一样,也返回重置的数据 + PaywayFee emptyData = PaywayFee.toEmptyData(item); + emptyData.setState(item.getState()); + emptyData.setApplymentSupport(item.getApplymentSupport()); + r.put(wayCode, emptyData); + } + + if ((paywayFee.getLevelList() == null ^ item.getLevelList() == null) + || (paywayFee.getCreditCardPaywayFee() == null ^ item.getCreditCardPaywayFee() == null)) { + // 银联模式不同步,也返回重置数据 + PaywayFee emptyData = PaywayFee.toEmptyData(item); + emptyData.setState(item.getState()); + emptyData.setApplymentSupport(item.getApplymentSupport()); + r.put(wayCode, emptyData); + } + } + }); + } + } + + /** + * 计算极限金额下产生最小的分润的交易金额 + * @param calBaseAmount + * @return + */ + public Long calMinTradeAmt(Long calBaseAmount) { + BigDecimal minProfitAmt = BigDecimal.valueOf(0.01); + return minProfitAmt.divide(feeRate,2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).longValue(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RuipayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RuipayApplymentInfo.java new file mode 100644 index 0000000..b737684 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RuipayApplymentInfo.java @@ -0,0 +1,257 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class RuipayApplymentInfo extends ApplymentBasicInfo { + + /** 入网方式 **/ + public String accessMode; + + /** 经营名称 **/ + public String merNameAbbr; + + /** 注册地址 **/ + public String regAddr; + + /** 经营范围 **/ + public String manaScop; + + /** 微信类目编号 **/ + public String wxlm; + + /** 账户性质 00:对公,01:对私 **/ + public String accountProp; + + /** + * 结算账户类型 小微不传 , + * 1:法人,2:非法人,3:对公 + * 账户性质为‘对公’时,传‘3’,对私时,传‘1’或‘2’ + **/ + public String settleType; + + /** 开户行编码 **/ + public String headBankNo; + + /** 开户支行信息 **/ + public String openBankMsg; + + + //******费率信息********** + + /** 结算类型 01:T1, 02:S0, 03:D1,04:D1+ **/ + public String settType; + + //******其他信息********** + + /** 终端数量 数值类型,小微商户最大20,普通商户最大9 **/ + public String termNum; + + /** 结算业务类型 01:T1, 02:S0, 03:D1,04:D1+ **/ + public String serviceType; + + /** 是否开通退款 0:是,1:否 **/ + public String tradeTypeReimburse; + + /** 是否进行微信实名认证 1:是,2:否 **/ + public String certificationType; + /** 经营类型 1:门店场所 2: 流动经营/便民服务 **/ + public String microBizType; + + /** 是否进行支付宝实名认证 1:是,2:否 **/ + public String alipayCertificationType; + /** 店铺注册地址 **/ + public String regAddress; + + + //******商户资料********** + + /** 商户协议照片 **/ + public String protocolPhoto; + + /** 营业场景照片一 **/ + public String businessScenePhoto1Img; + + /** 营业场景照片二 **/ + public String businessScenePhoto2Img; + + /** 商户附属协议 **/ + public String mchAffiliateAgreementImg; + + /** 结算授权书 **/ + public String settleAuthLetterImg; + + /** 商户协议类型 0:纸质协议(默认) + 1:电子协议(需要开通权限) **/ + public String pactType; + + /** 协议接收人 **/ + public String agreementName; + + /** 协议接收人电话 **/ + public String agreementPhone; + + /** 结算人是否为法人 1-是 0-否 **/ + public String isLegalInfo; + + /** 联系人是否为法人 1-是 0-否 **/ + public String contactSameToLegal; + + /** 受益人是否同法人 0:是 1:否 **/ + public String ifBenefit; + /** 受益人姓名 **/ + public String benefitCredPeople; + /** 受益人证件号 **/ + public String benefitCredNo; + /** 受益人身份证人像面照片 **/ + public String benefitCred1Img; + /** 受益人身份证国徽面照片 **/ + public String benefitCred2Img; + /** 受益人有效期开始 **/ + public String benefitCredStartTime; + /** 受益人有效期结束 **/ + public String benefitCredTime; + /** 受益人地址 **/ + public String benefitOperateAddr; + + + // 商户类型转换 1-个体 2-企业 7-小微商户 + public String coverMerchantType() { + Byte merchantType = this.merchantType; + String merType = ""; + switch (merchantType) { + case 1: { + merType = "7"; + break; + } + case 2: { + merType = "1"; + break; + } + case 3: { + merType = "2"; + break; + } + default: + merType = "6"; + } + return merType; + } + + // mcc转换 + public String coverMcc() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] code = this.mccCode.split("_"); + if (code[1].length() == 3) { + return "0" + code[1]; + } + return code[1]; + } + return null; + } + + // 有效期转换 + public String coverDateTime(String dateStr) { + if ("长期".equals(dateStr)) { + return ""; + } else { + return dateStr.replace("-", ""); + } + } + + // 结算账户类型转换 + public String coverSettAccountType() { + if (MchApplyment.MERCHANT_TYPE_INDIVIDUAL == this.merchantType) { + return "01"; + }else { + if ("B".equals(this.settAccountType)) { + return "00"; + } else { + return "01"; + } + } + } + + // 开户支行信息转换 例:四平市古城农村信用合作社_401243301421 + public String[] coverBranchBankMsg(String openBankMsg) { + if (StringUtils.isEmpty(openBankMsg)) { + return null; + } else { + return openBankMsg.split("_"); + } + } + + public void convertApplymentPayFee(JSONObject paperJson) { + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + // 费率 【以下费率配置以瑞银信机构配置】 新机构不一致情况 可按机构类型区分 + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + paperJson.put("wxDebitRate", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + paperJson.put("zfbDebitRate", convertRate(item.getFeeRate()) + ""); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 借记手续费 + paperJson.put("qrDebitRate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + // 借记手续费 + paperJson.put("debitRate", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记封顶 分 + paperJson.put("debitTop", AmountUtil.convertCent2Dollar(item.getMaxFee()) + ""); + } + // 贷记卡费率 + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 银联云闪付贷记卡费率(单笔交易≤1000元) 参数单位为‰ + paperJson.put("qrCreditRate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + paperJson.put("creditRate", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + } + } + }); + } + } + + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + public String coverBankAreaCode() { + if (this.getSettAccountBankBranchAreaCode().size() >= 3) { + return this.getSettAccountBankBranchAreaCode().get(2)+""; + }else { + return this.getSettAccountBankBranchAreaCode().get(1)+""; + } + } + + @Override + public String bankBranchNo() { + String[] strings = coverBranchBankMsg(openBankMsg); + if (strings == null) { + return null; + } else { + return strings[1]; + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RyxpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RyxpayApplymentInfo.java new file mode 100644 index 0000000..8eacdb0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/RyxpayApplymentInfo.java @@ -0,0 +1,694 @@ +package com.jeequan.jeepay.core.model.applyment; + + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; +import org.springframework.util.Assert; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class RyxpayApplymentInfo extends ApplymentBasicInfo { + + /** + * 商户类型 + * 00:聚合(默认) ,01 pos+聚合 + */ + private String merchType; + + private String posMerId; + + /** + * 入网方式 + */ + private String accessMode; + + /** + * 机构号 + */ + private String orgId; + + @JSONField(serialize = false) + public String getMerProp() { + if (merchantType.equals(MchApplyment.MERCHANT_TYPE_PERSONAL)) { + return "7"; + } + + if (merchantType.equals(MchApplyment.MERCHANT_TYPE_INDIVIDUAL)) { + return "1"; + } + + if (merchantType.equals(MchApplyment.MERCHANT_TYPE_ENTERPRISE)) { + return "2"; + } + + throw new BizException("未知的商户类型"); + } + + /** + * 商户简称 + * merProp=7时,不传 + * 用于银联银行卡交易报送,商户POS签购单打印名称等场景 + */ + @JSONField(serialize = false) + public String getMerName() { + return mchShortName; + } + + /** + * 商户营业执照上的名称, + * 用于向支付宝和微信进行报备和实名认证(经营证件类型为营业执照时,不需要传) + */ + @JSONField(serialize = false) + public String getOrgMerName() { + return mchFullName; + } + + /** + * 经营名称 + * 扫码交易时,收款成功页面展示的名称 + */ + @JSONField(serialize = false) + public String getMerNameAbbr() { + return mchShortName; + } + + /** + * 【商户性质】为“个体“、”企业“、”其他”、“党政、机关及事业单位”时,需要传该字段。 + * 00:普通,商户与商户没有关系 + * 01:连锁,可以使用统一营业执照,也可以使用自己的营业执照 + * 02:市场,多商户使用同一营业执照 + */ + private String merchRelp; + + /** + * 经营证件类型小微商户不传 + * 参考:商户性质与经营证件类型对应关系 + * 1, 营业执照 + */ + private String licType; + + /** + * 使用 licenseNo + * 经营证件号码 + * 小微商户不传 + */ + @JSONField(serialize = false) + public String getLicNum() { + return licenseNo; + } + + /** + * 经营证件有效期开始时间,使用 licenseEffectBegin + * 小微商户不传 + * 格式yyyyMMdd + */ + @JSONField(serialize = false) + public String getLicNumStartTime() { + Assert.notNull(licenseEffectBegin, "经营证件有效期开始时间不能为空"); + return licenseEffectBegin.replace("-", ""); + } + + /** + * 使用 licenseEffectEnd + * 经营证件有效期结束日期 + * 小微商户不传 + * 格式yyyyMMdd,长期传空 + */ + @JSONField(serialize = false) + public String getLicNumTime() { + Assert.notNull(licenseEffectEnd, "经营证件有效期截止时间不能为空"); + if ("长期".equals(licenseEffectEnd)) { + return ""; + } + + return licenseEffectBegin.replace("-", ""); + } + + /** + * 法人姓名, 小微商户不传 + * 需要与营业执照上的法人名称一致 + */ + @JSONField(serialize = false) + public String getCredPeople() { + return idcardName; + } + + /** + * 法人证件类型 + * 小微商户不传 + * 0105:身份证 + * 0202:护照 + * 0114:中国香港居民-来往内地通行证 + * 0115: 中国澳门居民-来往内地通行证 + * 0116: 中国台湾居民-来往大陆通行证 + * 0558:港澳居住证 + * 0557:台湾居住证 + * 0559:外国人永久居留证 + */ + @JSONField(serialize = false) + public String getCredType() { + return "0105"; + } + + /** + * 法人证件号 + * 小微商户不传 + */ + @JSONField(serialize = false) + public String getCredNo() { + return idcardNo; + } + + /** + * 法人证件有效期开始时间 + * 小微商户不传 + */ + @JSONField(serialize = false) + public String getCredStartTime() { + Assert.notNull(idcardEffectBegin, "法人身份证有效期开始时间不能为空"); + return idcardEffectBegin.replace("-", ""); + } + + /** + * 法人证件有效期截止时间 + * 小微商户不传 + */ + @JSONField(serialize = false) + public String getCredTime() { + Assert.notNull(idcardEffectEnd, "法人身份证有效期截止时间不能为空"); + if ("长期".equals(idcardEffectEnd)) { + return ""; + } + + return idcardEffectEnd.replace("-", ""); + } + + /** + * 商户入网县编码(银联码) + */ + @JSONField(serialize = false) + public String getCityArea() { + if (areaCode == null || areaCode.size() < 3) { + throw new BizException("缺少经营地区编码"); + } + return areaCode.getString(2); + } + + /** + * 经度 + */ + private String longitude; + + /** + * 纬度 + */ + private String latitude; + + /** + * 经营地址省(国标码) + */ + @JSONField(serialize = false) + public String getOperateProvince() { + if (areaCode == null || areaCode.isEmpty()) { + throw new BizException("缺少经营地区编码"); + } + return areaCode.getString(0); + } + + ; + + /** + * 经营地址市编码(国标码) + */ + @JSONField(serialize = false) + public String getOperateCity() { + if (areaCode == null || areaCode.size() < 2) { + throw new BizException("缺少经营地区编码"); + } + return areaCode.getString(1); + } + + /** + * 经营地址区编码(国标码) + */ + @JSONField(serialize = false) + public String getOperateArea() { + if (areaCode == null || areaCode.size() < 3) { + throw new BizException("缺少经营地区编码"); + } + return areaCode.getString(2); + } + + /** + * 联系人 + */ + @JSONField(serialize = false) + public String getContactPerson() { + return contactName; + } + + @JSONField(serialize = false) + public String getOperateAddr() { + return address; + } + + /** + * 注册地址 + */ + @JSONField(serialize = false) + public String getRegAddr() { + return mchAddress; + } + + /** + * 经营范围 + */ + @JSONField(serialize = false) + public String getManaScop() { + return mccName; + } + + @JSONField(serialize = false) + public String getMcc() { + return mccCode; + } + + /** + * 结算卡号 + */ + @JSONField(serialize = false) + public String getBankCard() { + return settAccountNo; + } + + /** + * 账户类型 + */ + @JSONField(serialize = false) + public String getAccountProp() { + if ("B".equals(settAccountType)) { + return "00"; + } + + if ("C".equals(settAccountType)) { + return "01"; + } + + throw new BizException("未知的账户类型"); + } + + /** + * 结算类型 + * 1:法人,2:非法人,3:对公 + * 账户性质为‘对公’时,传‘3’,对私时,传‘1’或‘2’ + */ + @JSONField(serialize = false) + public String getSettleType() { + if ("B".equals(settAccountType)) { + return "3"; + } + + if ("Y".equals(authSettle)) { + return "2"; + } else { + return "1"; + } + } + + /** + * 账户名 + */ + @JSONField(serialize = false) + public String getBankCardName() { + return settAccountName; + } + + /** + * 结算证件类型 + */ + @JSONField(serialize = false) + public String getSettleCredType() { + return "0105"; + } + + /** + * 结算证件号码 + */ + @JSONField(serialize = false) + public String getSettleCredNo() { + if (getSettleType().equals("2")) { + return settAccountIdcardNo; + } + + return idcardNo; + } + + /** + * 结算证件号码 + */ + @JSONField(serialize = false) + public String getSettleCredStartTime() { + if (getSettleType().equals("2")) { + Assert.notNull(settAccountIdcardEffectBegin, "缺少结算人证件的有效期开始时间"); + return settAccountIdcardEffectBegin.replace("-", ""); + } + + Assert.notNull(idcardEffectBegin, "缺少法人证件的有效期开始时间"); + return idcardEffectBegin.replace("-", ""); + } + + /** + * 结算证件有效期结束日期 + * 格式yyyyMMdd,长期传空 + */ + @JSONField(serialize = false) + public String getSettleCredTime() { + if (getSettleType().equals("2")) { + Assert.notNull(settAccountIdcardEffectEnd, "缺少结算人证件的有效期开始时间"); + if ("长期".equals(settAccountIdcardEffectEnd)) { + return ""; + } + + return settAccountIdcardEffectEnd.replace("-", ""); + } + + Assert.notNull(idcardEffectEnd, "缺少法人证件的有效期开始时间"); + if ("长期".equals(idcardEffectEnd)) { + return ""; + } + + return idcardEffectEnd.replace("-", ""); + } + + @JSONField(serialize = false) + public String getBankCityArea() { + if (settAccountBankBranchAreaCode == null || settAccountBankBranchAreaCode.size() < 3) { + throw new BizException("缺少开户支行县区编码"); + } + return settAccountBankBranchAreaCode.getString(2); + } + + /** + * 结算开户银行编码 + */ + @JSONField(serialize = false) + public String getHeadBankNo() { + return settAccountBankCode; + } + + + + @JSONField(serialize = false) + public String getOpenBankName() { + return settAccountBankBranchName; + } + + /** + * 结算开户支行编码 + */ + @JSONField(serialize = false) + public String getOpenBankChild() { + return settAccountBankBranchCode; + } + + /** + * 是否启用标准费率 + * 1:是,2:否。默认传2 + */ + private String modelType; + + /** + * 借记费率(%) + * 银联二维码交易额大于1000 + */ + private String debitRate; + + /** + * 借记封顶额(元) + * 银联二维码交易额大于1000 + */ + private String debitTop; + + /** + * 贷记费率(%) + * 针对银联二维码交易额大于1000的该字段必填 + */ + private String creditRate; + + /** + * 银联云闪付借记费率(%) + * 数值, 银联二维码交易额小于等于1000 + */ + private String qrDebitRate; + + /** + * 银联云闪付贷记费率(%) + * 数值,银联二维码交易额小于等于1000 + */ + private String qrCreditRate; + + /** + * 微信交易费率(%) + */ + private String wxDebitRate; + + /** + * 支付宝交易费率(%) + */ + private String zfbDebitRate; + + private String remark; + + /** + * 数值类型,小微商户最大20,普通商户最大9 + * 统一传1 + */ + private String termNum; + + /** + * 结算业务类型 + * 01:T1, 第二个工作日 9点到11点 + * 02: S0, + * 03: D1, 第二个自然日 9点到11点 + * 04:D1+ 第二个自然日 8点30左右打款 + */ + @JSONField(serialize = false) + public String getServiceType() { + if (CS.SETTLEMENT_TYPE.D1.equals(settlementType)) { + return "04"; + } + + if (CS.SETTLEMENT_TYPE.T1.equals(settlementType)) { + return "01"; + } + + throw new BizException("未知的结算方式"); + } + + /** + * 是否开通退款 + * 0:是,1:否 + */ + private String tradeTypeReimburse; + + /** + * 是否进行微信实名认证 + */ + private String certificationType; + + /** + * 是否进行支付宝实名认证 + */ + private String alipayCertificationType; + + /** + * 店铺注册地址 + * 在【是否进行支付宝实名认证】选择了“是”,“企业/个体/党政机关及事业单位/其他”必传 + */ + private String regAddress; + + /** + * 法人证件居住地址 + * “企业/个体/党政机关及事业单位/其他”必传 + */ + @JSONField(serialize = false) + public String getCredAddr() { + Assert.notNull(idcardAddress, "法人证件居住地址不能为空"); + return idcardAddress; + } + + @JSONField(serialize = false) + public String getContactSameToLegal() { + if (contactIdcardNo == null) { + return "1"; + } + + if (contactIdcardNo.equals(idcardNo)) { + return "1"; + } + + return "0"; + } + + /** + * 联系人证件类型 + * 0105:身份证 + * 0202:护照 + * 0114:中国香港居民-来往内地通行证 + * 0115: 中国澳门居民-来往内地通行证 + * 0116: 中国台湾居民-来往大陆通行证 + * 0558:港澳居住证 + * 0557:台湾居住证 + * 0559:外国人永久居留证 + */ + private String contactCredType; + + @JSONField(serialize = false) + public String getContactStartTime() { + if ("1".equals(getContactSameToLegal())) { + return idcardEffectBegin.replace("-", ""); + } + + Assert.notNull(contactIdcardEffectBegin, "联系人证件有效期开始时间不能为空"); + return contactIdcardEffectBegin.replace("-", ""); + } + + @JSONField(serialize = false) + public String getContactCardImg1() { + if ("1".equals(getContactSameToLegal())) { + return idcard1Img; + } + + Assert.notNull(contactIdcard1Img, "联系人证件卡号面不能为空"); + return contactIdcard1Img; + } + + @JSONField(serialize = false) + public String getContactCardImg2() { + if ("1".equals(getContactSameToLegal())) { + return idcard2Img; + } + + Assert.notNull(contactIdcard2Img, "联系人证件国徽面面不能为空"); + return contactIdcard2Img; + } + + + + /** + * 联系人证件有效期结束日期 + */ + @JSONField(serialize = false) + public String getContactTime() { + if ("1".equals(getContactSameToLegal())) { + return idcardEffectEnd.replace("-", ""); + } + + Assert.notNull(contactIdcardEffectEnd, "联系人证件有效期开始时间不能为空"); + return contactIdcardEffectEnd.replace("-", ""); + } + + /** + * 联系人身份证号 + */ + @JSONField(serialize = false) + public String getContactPersonCred() { + if ("1".equals(getContactSameToLegal())) { + return idcardNo; + } + + return contactIdcardNo; + } + + /** + * 经营类型 + * 开通微信实名认证,商户性质为‘市场‘或’连锁‘或‘小微商户‘时,必传。(certificationType=1,merPro=3|5|7) + * 1:门店场所 + * 2: 流动经营/便民服务 + */ + private String microBizType; + + /** + * 支付授权目录 + * 多条数据,用逗号分隔 + */ + private String jsapiPath; + + private String subAppid; + + /** + * 商户协议类型 + * 0:纸质协议(默认) + * 1:电子协议(需要开通权限) + */ + private String pactType; + + // 受益人信息不填 + + + public void collRateInfo(JSONObject result) { + paywayFeeList.forEach(item -> { + // 线上费率 + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + result.put("wxDebitRate", convertRate(item.getFeeRate())); + result.put("zfbDebitRate", convertRate(item.getFeeRate())); + + result.put("qrDebitRate", convertRate(item.getFeeRate())); + // 费率 + result.put("debitRate", convertRate(item.getFeeRate())); + // 封顶 + result.put("debitTop", "20"); + result.put("qrCreditRate", convertRate(item.getFeeRate())); + result.put("creditRate", convertRate(item.getFeeRate())); + + return; + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + result.put("wxDebitRate", convertRate(item.getFeeRate())); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + result.put("zfbDebitRate", convertRate(item.getFeeRate())); + } + + // 云闪付费率 + if (item.getWayCode().startsWith("YSF_")) { + List levelList = item.getLevelList(); + // 借记卡费率 + levelList.forEach(ysfItem -> { + if (ysfItem.getMaxFee() == 100000L) { + result.put("qrDebitRate", convertRate(ysfItem.getFeeRate())); + } else { + // 费率 + result.put("debitRate", convertRate(ysfItem.getFeeRate())); + // 封顶 + result.put("debitTop", "20"); + } + }); + + // 贷记卡费率 + List creditLevelList = item.getCreditCardPaywayFee().getLevelList(); + creditLevelList.forEach(creditYsfItem -> { + if (creditYsfItem.getMaxFee() == 100000L) { + result.put("qrCreditRate", convertRate(creditYsfItem.getFeeRate())); + } else { + // 费率 + result.put("creditRate", convertRate(creditYsfItem.getFeeRate())); + } + }); + } + }); + } + + private String convertRate(BigDecimal rate) { + return rate.multiply(BigDecimal.valueOf(100)).stripTrailingZeros().toPlainString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SftpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SftpayApplymentInfo.java new file mode 100644 index 0000000..d77ab66 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SftpayApplymentInfo.java @@ -0,0 +1,113 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +@Data +public class SftpayApplymentInfo extends ApplymentBasicInfo { + + public final static String IDENTIFICATION_TYPE_MAINLAND_IDCARD = "IDENTIFICATION_TYPE_MAINLAND_IDCARD"; // 中国大陆居民-身份证 + public final static String IDENTIFICATION_TYPE_OVERSEA_PASSPORT = "IDENTIFICATION_TYPE_OVERSEA_PASSPORT"; // 其他国家或地区居民-护照 + public final static String IDENTIFICATION_TYPE_HONGKONG = "IDENTIFICATION_TYPE_HONGKONG"; // 中国香港居民–来往内地通行证 + public final static String IDENTIFICATION_TYPE_MACAO = "IDENTIFICATION_TYPE_MACAO"; // 中国澳门居民–来往内地通行证 + public final static String IDENTIFICATION_TYPE_TAIWAN = "IDENTIFICATION_TYPE_TAIWAN"; // 中国台湾居民–来往大陆通行证 + + /** 超级管理员类型 */ + protected String contactType; + + /** 超级管理员身份证件号码 */ + protected String contactIdNumber; + + /** 超管身份证人像面照片 */ + protected String contactIdDocCopy; + + /** 超管身份证国徽面照片 */ + protected String contactIdDocCopyBack; + + /** 超管身份证起始有效期 */ + protected String contactIdDocPeriodBegin; + + /** 超管身份证结束有效期 */ + protected String contactIdDocPeriodEnd; + + /** 业务办理授权函 */ + protected String businessAuthorizationLetter; + + /** 店铺名称 */ + protected String storeName; + + /** 店铺链接 */ + protected String storeUrl; + + /** 店铺二维码 */ + protected String storeQrCode; + + /** 小程序appId */ + protected String miniProgramSubAppid; + + /** 页面展示用开户行,实际传值使用父类的开户行名称 */ + protected String accountBankNameShow; + + /** 是否需要传入分支 */ + protected String needBankBranch; + + /** 银行别名编码,请求银行分支时使用 */ + protected String bankAliasCode; + + /** 入驻结算规则ID */ + protected Integer settlementId; + + /** 所属行业 */ + protected String qualificationType; + + /** 是否需要上传特殊资质 */ + protected Boolean isNeedQualification; + + /** 特殊资质 */ + protected String qualifications; + + /** 法人是否为受益人 */ + protected Boolean owner; + + + /** 主体类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertMerchantType(Byte merchantType){ + + if(merchantType == null){ + return null; + } + + if(merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "2401"; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL_SELLER){ + return "2500"; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "4"; + }else if(merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "2"; + } + return null; + } + + /** 结算账号类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertSettAccountType(String settAccountType){ + + if(StringUtils.isEmpty(settAccountType)){ + return null; + } + + if(settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE)){ + return "74"; + }else if(settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL)){ + return "75"; + } + return null; + } + + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ShengpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ShengpayApplymentInfo.java new file mode 100644 index 0000000..b04b30a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ShengpayApplymentInfo.java @@ -0,0 +1,284 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.utils.AmountUtil; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.Arrays; + +@Data +public class ShengpayApplymentInfo extends ApplymentBasicInfo { + + /** 分账费用费率, 单位: 百分比, 传入的为实际费率值 1% 传入的为 0.01 */ + private BigDecimal divisionFeeRate; + + /** pos信息集合 */ + private String posListStr; + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertMerchantType(){ + + if(this.merchantType == null){ + return null; + } + + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "PERSONAL"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "INDIVIDUAL"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "ENTERPRISE"; + } + return ""; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertLicenseEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.licenseEffectEnd) ? "2199-12-31" : this.licenseEffectEnd; // 盛付通 长期需要传入: 2199-12-31 + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertIdcardEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.idcardEffectEnd) ? "2199-12-31" : this.idcardEffectEnd; // 盛付通 长期需要传入: 2199-12-31 + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertSettAccountIdcardEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.settAccountIdcardEffectEnd) ? "2199-12-31" : this.settAccountIdcardEffectEnd; // 盛付通 长期需要传入: 2199-12-31 + } + + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertPaywayFeeList2String(){ + + // 签约产品不存在 && 不包含分账产品 + if(this.paywayFeeList == null && (this.getIsDivision() == null || this.getIsDivision() != CS.YES) ){ + return null; + } + + JSONArray result = new JSONArray(); + + // pos产品的费率信息 + PaywayFee posPaywayFee = null; + + // 签约收单产品 集合 + if(this.paywayFeeList != null){ + + for (PaywayFee paywayFee : this.paywayFeeList) { + + if(CS.PAY_WAY_CODE.AUTO_POS.equals(paywayFee.getWayCode())){ + posPaywayFee = paywayFee; + } + + JSONObject json = new JSONObject(); + + // 第一步: 转换产品ID ( 本系统 --》 盛付通 ) + String bizProductCode = null; + switch (paywayFee.getWayCode()){ + case CS.PAY_WAY_CODE.WX_BAR: bizProductCode = "OFFLINE_WX_SCAN"; break; + case CS.PAY_WAY_CODE.WX_JSAPI: bizProductCode = "OFFLINE_WX_JSAPI"; break; + case CS.PAY_WAY_CODE.WX_H5: bizProductCode = null; break; + case CS.PAY_WAY_CODE.WX_LITE: bizProductCode = "OFFLINE_WX_LITE"; break; + case CS.PAY_WAY_CODE.WX_NATIVE: bizProductCode = null; break; + case CS.PAY_WAY_CODE.ALI_BAR: bizProductCode = "OFFLINE_ALIPAY_SCAN"; break; + case CS.PAY_WAY_CODE.ALI_JSAPI: bizProductCode = "OFFLINE_ALIPAY_JSAPI"; break; + case CS.PAY_WAY_CODE.ALI_LITE: bizProductCode = "OFFLINE_ALIPAY_LITE"; break; + case CS.PAY_WAY_CODE.ALI_PC: bizProductCode = ""; break; + case CS.PAY_WAY_CODE.ALI_QR: bizProductCode = "OFFLINE_ALIPAY_QR"; break; + case CS.PAY_WAY_CODE.ALI_WAP: bizProductCode = ""; break; + case CS.PAY_WAY_CODE.UP_BAR: bizProductCode = "OFFLINE_UNIONPAY_SCAN_D"; break; //银联条码借记卡支付 (付款码 用户被扫) + case CS.PAY_WAY_CODE.UP_QR: bizProductCode = "OFFLINE_UNIONPAY_QR_D"; break; //银联扫码借记卡支付 (二维码 用户主扫) + case CS.PAY_WAY_CODE.UP_JSAPI: bizProductCode = "OFFLINE_UNIONPAY_QUICK_D"; break; //银联行业码借记卡支付 (jsapi) + + case CS.PAY_WAY_CODE.YSF_BAR: bizProductCode = "OFFLINE_UNIONPAY_SCAN_D"; break; //银联条码借记卡支付 (付款码 用户被扫) + case CS.PAY_WAY_CODE.YSF_JSAPI: bizProductCode = "OFFLINE_UNIONPAY_QUICK_D"; break; //银联行业码借记卡支付 (jsapi) + + } + + // 盛付通不存在该产品 + if(StringUtils.isEmpty(bizProductCode)){ + continue; + } + + // 产品编码 + json.put("bizProductCode", bizProductCode); + + // 单笔费率 + if(PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())){ + json.put("feeType", "SINGLE_FEE"); + JSONObject feeInfo = JsonKit.newJson("feeValue", convertRate(paywayFee.getFeeRate())); + json.put("feeInfos", Arrays.asList(feeInfo)); + result.add(json); + continue; + } + + // 以下为阶梯费率 + json.put("feeType", "STAIR_FEE"); + json.put("minFee", convertFee(paywayFee.getMinFee())); + json.put("maxFee", convertFee(paywayFee.getMaxFee())); + JSONArray feeInfos = new JSONArray(); + + if(paywayFee.getLevelList() != null){ + for (PaywayFee feeItem : paywayFee.getLevelList()) { + JSONObject feeInfo = new JSONObject(); + feeInfo.put("feeValue",convertRate(feeItem.getFeeRate())); + feeInfo.put("minValue",convertFee(feeItem.getMinFee())); + feeInfo.put("maxValue",convertFee(feeItem.getMaxFee())); + feeInfos.add(feeInfo); + } + } + + json.put("feeInfos", feeInfos); + + result.add(json); + + // 设置银联贷记卡相关参数 + if("OFFLINE_UNIONPAY_SCAN_D".equals(bizProductCode) || "OFFLINE_UNIONPAY_QR_D".equals(bizProductCode) || "OFFLINE_UNIONPAY_QUICK_D".equals(bizProductCode)){ + if(paywayFee.getCreditCardPaywayFee() != null){ + JSONObject jsonByCredit = new JSONObject(); + // 产品编码 + if("OFFLINE_UNIONPAY_SCAN_D".equals(bizProductCode)) jsonByCredit.put("bizProductCode", "OFFLINE_UNIONPAY_SCAN_C"); + if("OFFLINE_UNIONPAY_QR_D".equals(bizProductCode)) jsonByCredit.put("bizProductCode", "OFFLINE_UNIONPAY_QR_C"); + if("OFFLINE_UNIONPAY_QUICK_D".equals(bizProductCode)) jsonByCredit.put("bizProductCode", "OFFLINE_UNIONPAY_QUICK_C"); + + jsonByCredit.put("feeType", "STAIR_FEE"); + jsonByCredit.put("minFee", convertFee(paywayFee.getCreditCardPaywayFee().getMinFee())); + jsonByCredit.put("maxFee", convertFee(paywayFee.getCreditCardPaywayFee().getMaxFee())); + JSONArray feeInfosByCredit = new JSONArray(); + + if(paywayFee.getCreditCardPaywayFee().getLevelList() != null){ + for (PaywayFee feeItem : paywayFee.getCreditCardPaywayFee().getLevelList()) { + JSONObject feeInfo = new JSONObject(); + feeInfo.put("feeValue",convertRate(feeItem.getFeeRate())); + feeInfo.put("minValue",convertFee(feeItem.getMinFee())); + feeInfo.put("maxValue",convertFee(feeItem.getMaxFee())); + feeInfosByCredit.add(feeInfo); + } + } + + jsonByCredit.put("feeInfos", feeInfosByCredit); + result.add(jsonByCredit); + } + } + + } + } + + // 分账 + if(this.getIsDivision() != null && this.getIsDivision() == CS.YES){ + + JSONObject json = new JSONObject(); + json.put("bizProductCode", "SHARING"); + json.put("feeType", "SINGLE_FEE"); // SINGLE_FEE单笔费率,0.0075,千分之7.5 ; SINGLE_QUOTA单笔定额,0.01,一笔固定收取0.01元 + json.put("feeInfos", Arrays.asList(JsonKit.newJson("feeValue", this.divisionFeeRate))); + result.add(json); + } + + + // pos产品 + if(posPaywayFee != null){ + + // -------- POS银联借记卡支付 -------- + JSONObject posDebitCard = new JSONObject(); + posDebitCard.put("bizProductCode", "POS_DEBIT_CARD"); + posDebitCard.put("feeType", "STAIR_FEE"); + + JSONArray feeInfos = new JSONArray(); + if(posPaywayFee.getLevelList() != null){ + for (PaywayFee feeItem : posPaywayFee.getLevelList()) { + JSONObject feeInfo = new JSONObject(); + feeInfo.put("feeValue",convertRate(feeItem.getFeeRate())); + feeInfo.put("minValue",convertFee(feeItem.getMinFee())); + feeInfo.put("maxValue",convertFee(feeItem.getMaxFee())); + feeInfos.add(feeInfo); + } + } + posDebitCard.put("feeInfos", feeInfos); + posDebitCard.put("minFee", convertFee(posPaywayFee.getMinFee())); + posDebitCard.put("maxFee", convertFee(posPaywayFee.getMaxFee())); + result.add(posDebitCard); + + // -------- POS银联借记卡支付 -------- + + + // -------- POS银联借记卡支付优惠 -------- + JSONObject posDebitCardDis = new JSONObject(); + posDebitCardDis.put("bizProductCode", "POS_DEBIT_CARD_DIS"); + posDebitCardDis.put("feeType", "SINGLE_FEE"); + posDebitCardDis.put("feeInfos", Arrays.asList(JsonKit.newJson("feeValue", convertRate(posPaywayFee.getLevelList().get(0).getFeeRate())))); + result.add(posDebitCardDis); + + // -------- POS银联借记卡支付优惠 -------- + + // -------- POS银联贷记卡支付 -------- + JSONObject posCreditCard = new JSONObject(); + posCreditCard.put("bizProductCode", "POS_CREDIT_CARD"); + posCreditCard.put("feeType", "SINGLE_FEE"); + posCreditCard.put("feeInfos", Arrays.asList(JsonKit.newJson("feeValue", convertRate(posPaywayFee.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())))); + result.add(posCreditCard); + + // -------- POS银联贷记卡支付 -------- + + // -------- POS银联贷记卡支付优惠 -------- + JSONObject posCreditCardDis = new JSONObject(); + posCreditCardDis.put("bizProductCode", "POS_CREDIT_CARD_DIS"); + posCreditCardDis.put("feeType", "SINGLE_FEE"); + posCreditCardDis.put("feeInfos", Arrays.asList(JsonKit.newJson("feeValue", convertRate(posPaywayFee.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())))); + result.add(posCreditCardDis); + + // -------- POS银联贷记卡支付优惠 -------- + } + + return result.toJSONString(); + + } + + + private BigDecimal convertRate(BigDecimal rate){ + return rate == null ? null : rate.setScale(4, BigDecimal.ROUND_HALF_UP); + } + + private BigDecimal convertFee(Long fee){ + + if(fee == null){ + return null; + } + + return new BigDecimal(AmountUtil.convertCent2Dollar(fee)).setScale(2, BigDecimal.ROUND_HALF_UP); + } + + + public String convertTerminalInfos(){ + + if(StringUtils.isEmpty(this.getPosListStr())){ + return null; + } + + JSONArray result = new JSONArray(); + + JSONArray jsonArray = JSONArray.parseArray(this.getPosListStr()); + for (Object o : jsonArray) { + JSONObject item = (JSONObject) o; + + JSONObject itemNew = new JSONObject(); + itemNew.put("ticketName", item.getString("ticketName")); + itemNew.put("terminalCount", item.getIntValue("terminalCount")); + itemNew.put("terminalCityId", item.getJSONArray("terminalCityId").get(1).toString()); //城市编号 + itemNew.put("terminalDetailAddress", item.getString("terminalDetailAddress")); + result.add(itemNew); + } + + return result.toJSONString(); + } + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SxfpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SxfpayApplymentInfo.java new file mode 100644 index 0000000..6b6acdf --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/SxfpayApplymentInfo.java @@ -0,0 +1,1044 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; +import org.springframework.util.Assert; + +import java.math.BigDecimal; +import java.util.*; + +@Data +public class SxfpayApplymentInfo extends ApplymentBasicInfo { + + /** + * 签购单名称,不传则与商户简称保持一致 + */ + private String merName; + + /** + * 商户简称,使用 mchShortName + */ + @JSONField(serialize = false) + public String getMecDisNm() { + return mchShortName; + } + + /** + * 商户联系手机号,使用 contactPhone + */ + @JSONField(serialize = false) + public String getMblNo() { + return contactPhone; + } + + /** + * 经营类型,枚举值 + * 01 线下 + * 02 线上 + * 03 非盈利类 + * 04 缴费类 + * 05 保险类 + * 06 私立院校 + */ + private String operationalType; + + /** + * 通过商户类型 merchantType来判断 + */ +// private String haveLicenseNo; + + /** + * 资质类型,枚举值 + * 取值范围: + * 01 自然人 + * 02 个体户 + * 03 企业 + * 04 政府机关 + * 05 事业单位 + * 06 其他组织 + * mecTypeFlag=01(连锁总店)或03(1+N总店)时,此处不能选自然人; + * mecTypeFlag=04(1+n分店)时仅能选自然人; + * 线上商户需选择03企业/04政府机关/05事业单位/06其他组织; + */ + @JSONField(serialize = false) + public String getHaveLicenseNo() { + if (merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL) { + return "01"; + } + + if (merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL) { + return "02"; + } + + if (merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE) { + return "03"; + } + + throw new BizException("未知的资质类型"); + } + + /** + * 商户类型,枚举值 + * 取值范围: + * 00 普通单店商户, 默认使用该值 + * 01 连锁总店 + * 02 连锁分店 + * 03 1+N总店 + * 04 1+N分店 + * mecTypeFlag == 02(连锁分店)时需校验所属总店mecTypeFlag必须为01 连锁总店, + * mecTypeFlag == 04(1+n分店)时需校验所属总店mecTypeFlag必须为03 1+n总店; + */ + private String mecTypeFlag; + + /** + * 所属总店商户编号,当mecTypeFlag==04 时必传 + */ + private String parentMno; + + /** + * 连锁分店是否独立结算,枚举值 + * 取值范围: + * 00 独立结算 + * 01 非独立结算 + * 商户类型(mecTypeFlag==02)连锁分店时必传此参数;其他情况传入无效 + */ + private String independentModel; + + /** + * 线上产品类型,枚举值 + * 取值范围: + * 01 APP + * 02 网站 + * 03 公众号/小程序/服务窗 + * 经营类型为线上(operationalType=='02')时,本字段必填 + */ + private String onlineType; + + /** + * APP名称/网站网址/公众号/小程序/服务窗名称 + * 经营类型为线上(operationalType=='02')时,本字段必填 + */ + private String onlineName; + + /** + * APP/网站/公众号/小程序/服务窗下载地址及账号信息 + */ + private String onlineTypeInfo; + + /** + * 使用areaCode + * 注册地址省编码 + * 需要与营业执照照面一致; + * 省、市、区编码、街道地址(四个参数需同时上传) + */ + @JSONField(serialize = false) + public String getProvCd() { + if (areaCode.isEmpty()) { + throw new BizException("地区编码不能为空"); + } + + return areaCode.getString(0); + } + + /** + * 使用areaCode + * 注册地址市编码 + * 需要与营业执照照面一致; + * 省、市、区编码、街道地址(四个参数需同时上传) + */ + @JSONField(serialize = false) + public String getCityCd() { + if (areaCode.size() < 2) { + throw new BizException("地区市编码不能为空"); + } + + return areaCode.getString(1); + } + + /** + * 使用areaCode + * 注册地址区编码 + * 需要与营业执照照面一致; + * 省、市、区编码、街道地址(四个参数需同时上传) + */ + @JSONField(serialize = false) + public String getDistCd() { + if (areaCode.size() < 3) { + throw new BizException("地区区编码不能为空"); + } + + return areaCode.getString(2); + } + + /** + * 使用address + * 注册地址街道地址 + * 直接填写详细街道门牌号即可; + * 省、市、区编码、街道地址(四个参数需同时上传) + */ + @JSONField(serialize = false) + public String getDetailAddress() { + return address; + } + + /** + * 使用address + * 商户实际经营详细地址 + * 直接填写详细街道门牌号即可 + */ + @JSONField(serialize = false) + public String getCprRegAddr() { + return address; + } + + /** + * 使用areaCode + * 实际经营地址省编码 + */ + @JSONField(serialize = false) + public String getRegProvCd() { + if (areaCode.isEmpty()) { + throw new BizException("地区编码不能为空"); + } + + return areaCode.getString(0); + } + + /** + * 使用areaCode + * 实际经营地址市编码 + */ + @JSONField(serialize = false) + public String getRegCityCd() { + if (areaCode.size() < 2) { + throw new BizException("地区市编码不能为空"); + } + + return areaCode.getString(1); + } + + /** + * 使用areaCode + * 实际经营地址区编码 + */ + @JSONField(serialize = false) + public String getRegDistCd() { + if (areaCode.size() < 3) { + throw new BizException("地区区编码不能为空"); + } + + return areaCode.getString(2); + } + + /** + * 使用mccCode + * 经营类目MCC + * 请选择正确MCC入网。 + * 参加AT活动(蓝海/微信智慧餐饮/微信高校食堂)的商户,为确保报名成功,请按照上游要求(详见活动报名接口)的MCC进件。 + */ + @JSONField(serialize = false) + public String getMccCd() { + return mccCode; + } + + /** + * 客服电话 + * 纯数字 + */ + @JSONField(serialize = false) + public String getCsTelNo() { + return contactPhone; + } + + /** + * 邮箱 + * 此字段将上送至微信、支付宝 + */ + private String email; + + /** + * 二维码费率(%) + * rateType 枚举值,取值范围: + *

+ * 同时上送以下四个枚举值; + * 01 微信费率 + * 02 支付宝费率 + * 06 银联单笔小于等于1000费率 + * 07 银联单笔大于1000费率 + *

+ * 或同时上送以下七个枚举值; + * 01 微信费率 + * 02 支付宝费率 + * 06 银联单笔小于1000贷记卡费率 + * 061 银联单笔小于1000借记卡费率 + * 07 银联单笔大于1000贷记卡费率 + * 071 银联单笔大于1000借记卡费率 + * 072 银联单笔大于1000借记卡封顶手续费 + *

+ * 或同时上送以下十一个枚举值 + * 01 微信贷记卡费率 + * 011微信借记卡费率 + * 012微信借记卡封顶手续费 + * 02 支付宝贷记卡费率 + * 021 支付宝借记卡费率 + * 022 支付宝借记卡封顶手续费 + * 06 银联单笔小于1000贷记卡费率 + * 061 银联单笔小于1000借记卡费率 + * 07 银联单笔大于1000贷记卡费率 + * 071 银联单笔大于1000借记卡费率 + * 072 银联单笔大于1000借记卡封顶手续费 + *

+ * 或同时上送以下十四个枚举值 + * 01 微信贷记卡费率 + * 011微信借记卡费率 + * 012微信借记卡封顶手续费 + * 02 支付宝贷记卡费率 + * 021 支付宝借记卡费率 + * 022 支付宝借记卡封顶手续费 + * 03 翼支付贷记卡费率 + * 031 翼支付借记卡费率 + * 032 翼支付借记卡封顶手续费 + * 06 银联单笔小于1000贷记卡费率 + * 061 银联单笔小于1000借记卡费率 + * 07 银联单笔大于1000贷记卡费率 + * 071 银联单笔大于1000借记卡费率 + * 072 银联单笔大于1000借记卡封顶手续费 + */ + private List qrcodeList; + + /** + * 返回费率信息 + * + * @return + */ + public List collQrCodeList() { + Map result = new HashMap(); + paywayFeeList.forEach(item -> { + // 线上费率 + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.WX_CREDIT_RATE); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.WX_CREDIT_RATE, rateInfo); + + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.ALI_CREDIT_RATE); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.ALI_CREDIT_RATE, rateInfo); + + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_LT_1000); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.YSF_DEBIT_RATE_LT_1000, rateInfo); + + // 费率 + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_GT_1000); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.YSF_DEBIT_RATE_GT_1000, rateInfo); + + // 封顶 + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_GT_1000_TOP); + rateInfo.setRate("20"); + result.put(RateInfo.YSF_DEBIT_RATE_GT_1000_TOP, rateInfo); + + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_CREDIT_RATE_LT_1000); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.YSF_CREDIT_RATE_LT_1000, rateInfo); + + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_CREDIT_RATE_GT_1000); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.YSF_CREDIT_RATE_GT_1000, rateInfo); + + return; + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.WX_CREDIT_RATE); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.WX_CREDIT_RATE, rateInfo); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.ALI_CREDIT_RATE); + rateInfo.setRate(convertRate(item.getFeeRate())); + result.put(RateInfo.ALI_CREDIT_RATE, rateInfo); + } + + // 云闪付费率 + if (item.getWayCode().startsWith("YSF_")) { + List levelList = item.getLevelList(); + // 借记卡费率 + levelList.forEach(ysfItem -> { + if (ysfItem.getMaxFee() == 100000L) { + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_LT_1000); + rateInfo.setRate(convertRate(ysfItem.getFeeRate())); + result.put(RateInfo.YSF_DEBIT_RATE_LT_1000, rateInfo); + } else { + // 费率 + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_GT_1000); + rateInfo.setRate(convertRate(ysfItem.getFeeRate())); + result.put(RateInfo.YSF_DEBIT_RATE_GT_1000, rateInfo); + + // 封顶 + rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_DEBIT_RATE_GT_1000_TOP); + rateInfo.setRate("20"); + result.put(RateInfo.YSF_DEBIT_RATE_GT_1000_TOP, rateInfo); + } + }); + + // 贷记卡费率 + List creditLevelList = item.getCreditCardPaywayFee().getLevelList(); + creditLevelList.forEach(creditYsfItem -> { + if (creditYsfItem.getMaxFee() == 100000L) { + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_CREDIT_RATE_LT_1000); + rateInfo.setRate(convertRate(creditYsfItem.getFeeRate())); + result.put(RateInfo.YSF_CREDIT_RATE_LT_1000, rateInfo); + } else { + // 费率 + RateInfo rateInfo = new RateInfo(); + rateInfo.setRateType(RateInfo.YSF_CREDIT_RATE_GT_1000); + rateInfo.setRate(convertRate(creditYsfItem.getFeeRate())); + result.put(RateInfo.YSF_CREDIT_RATE_GT_1000, rateInfo); + } + }); + } + }); + + return new ArrayList<>(result.values()); + } + + private String convertRate(BigDecimal rate) { + return rate.multiply(BigDecimal.valueOf(100)).stripTrailingZeros().toPlainString(); + } + + /** + * 刷卡费率(费率单位为%,封顶值单位为元) + *

+ * json格式传入: + * 21 贷记卡费率,不传默认0.60 + * 22 借记卡费率,不传默认0.55 + * 23 借记卡手续费封顶值,不传默认25 + * 24 云闪付贷记卡费率,不传默认银联二维码1000以上贷记卡费率 + * 25 云闪付的借记卡费率,不传默认银联二维码1000以上贷记卡费率 + *

+ * 若传入则对应(21,22,23)三个类型必须同时传入 + * 若传入24,则25必须同时传入 + */ + private List bankCardRates; + + /** + * 行业规则ID,枚举值: + * 00 标准类 + * 01 服饰鞋包、美妆日化、健身运动服务类 + *

+ * 仅资质类型为企业/个体户且MCC为《涉及MCC》内的MCC支持传入,不传系统默认 00 标准类 + */ + private String businessRule; + + /** + * 结算类型,枚举值 + * 取值范围: + * 03 T1结算 + * 04 D1结算 + * 不传值时,系统会根据合作机构签约时的默认结算产品执行。 + */ + @JSONField(serialize = false) + public String getSettleType() { + if (CS.SETTLEMENT_TYPE.D1.equals(settlementType)) { + return "04"; + } + + if (CS.SETTLEMENT_TYPE.T1.equals(settlementType)) { + return "03"; + } + + throw new BizException("未知的结算方式"); + } + + /** + * 银行卡预授权开关,枚举值 + * 取值范围: + * 01 关闭 + * 02 开通 + */ + private String bankCardPreAuthorization; + + /** + * 二维码预授权开关,枚举值 + * 取值范围: + * 01 关闭 + * 02 开通 + */ + private String qrCodePreAuthorization; + + /** + * 指定微信渠道号 + * 多渠道号情况下使用,进件到指定微信渠道号下 + */ + private String specifyWechatChannel; + + /** + * 指定支付宝PID + */ + private String specifyALiPayChannel; + + /** + * 回调地址 + * 说明:天阙平台支持推送商户入驻审核的终态结果给该地址,推送格式参见接口【入驻审核结果通知】 + * 如果不传,则依赖入驻结果查询接口获取审核最终状态 + */ + private String callbackUrl; + + /** + * 复核回调地址 + * 说明:传入则在商户入网状态为【入驻通过】时,返回复核标识及补充资料内容推送至该地址,推送格式参照接口【复核结果通知】 + */ + private String checkCallbackUrl; + + /** + * 使用mchFullName + * 营业执照注册名称 + * 需确保和营业执照照片一致,如果个体户营业执照中没有注册名称或注册名称是*,此处需要按照"个体户+法人姓名"的格式传入。 + * 资质类型为个体户、企业、政府机关、事业单位、其他组织(haveLicenseNo==02/03/04/05/06)时,本字段必填 + */ + @JSONField(serialize = false) + public String getCprRegNmCn() { + return mchFullName; + } + + /** + * 营业执照注册号 + * 营业执照号/统一信用编码。 + * 资质类型为个体户、企业、政府机关、事业单位、其他组织(haveLicenseNo==02/03/04/05/06)时,本字段必填 + */ + @JSONField(serialize = false) + public String getRegistCode() { + return licenseNo; + } + + /** + * 是否三证合一,枚举值 + * 取值范围: + * 00 是 + * 01 否 + * 资质类型为企业、政府机关、事业单位、其他组织(haveLicenseNo==03/04/05/06)时,本字段必填 + */ + @JSONField(serialize = false) + public String getLicenseMatch() { + return "00"; + } + + /** + * 组织机构代码 + */ + private String orgCode; + + /** + * 税务登记号 + */ + private String taxRegNo; + + /** + * 使用licenseEffectBegin + *

+ * 营业执照起始日 + * 格式为:YYYYMMDD + * 营业执照起始日、营业执照到期日需同时上传 + */ + @JSONField(serialize = false) + public String getBusinessLicStt() { + Assert.notNull(licenseEffectBegin, "营业执照起始日不能为空"); + + return licenseEffectBegin.replace("-", ""); + } + + /** + * 营业执照到期日 + * 格式为:YYYYMMDD + * 营业执照起始日、营业执照到期日需同时上传 + * 长期有效请传29991231 + */ + @JSONField(serialize = false) + public String getBusinessLicEnt() { + Assert.notNull(licenseEffectEnd, "营业执照截止日期不能为空"); + + if ("长期".equals(licenseEffectEnd)) { + return "29991231"; + } + + return licenseEffectEnd.replace("-", ""); + } + + /** + * 法人/商户负责人姓名 + */ + @JSONField(serialize = false) + public String getIdentityName() { + return idcardName; + } + + /** + * 法人/商户负责人证件类型,枚举值 + * 取值范围: + * 00 身份证 + * 05 港澳居民往来内地通行证 + * 06 台湾居民来往大陆通行证 + * 07 护照 + * 99 其他 + */ + private String identityTyp; + + /** + * 法人/商户负责人证件号 + */ + @JSONField(serialize = false) + public String getIdentityNo() { + return idcardNo; + } + + /** + * 法人身份证有效期开始时间 + */ + @JSONField(serialize = false) + public String getLegalPersonLicStt() { + Assert.notNull(idcardEffectBegin, "法人/商户负责人证件起始日不能为空"); + + return idcardEffectBegin.replace("-", ""); + } + + /** + * 法人/商户负责人证件到期日 + * 格式为:YYYYMMDD + * 长期有效请传29991231 + * + * @return + */ + @JSONField(serialize = false) + public String getLegalPersonLicEnt() { + Assert.notNull(idcardEffectBegin, "法人/商户负责人证件到期日不能为空"); + + if (idcardEffectEnd.equals("长期")) { + return "29991231"; + } + + return idcardEffectEnd.replace("-", ""); + } + + /** + * 结算账户名 + * 说明:自然人商户、线上类商户不允许授权结算。对公结算账户名与注册名没有包含关系时,需上传授权函。 + * + * @return + */ + @JSONField(serialize = false) + public String getActNm() { + return settAccountName; + } + + /** + * 使用 settAccountType + * 结算账户类型,枚举值 + * 取值范围: + * 00 对公 + * 01 对私 + * 说明:自然人商户只允许对私结算;线上商户只允许对公结算 + */ + @JSONField(serialize = false) + public String getActTyp() { + if ("B".equals(settAccountType)) { + return "00"; + } + + if ("C".equals(settAccountType)) { + return "01"; + } + + throw new BizException("未知的结算账户类型"); + } + + /** + * 结算人证件类型,枚举值 + * 取值范围: + * 00 身份证 + * 05 港澳居民往来内地通行证 + * 06 台湾居民来往大陆通行证 + * 07 护照 + * 99 其他 + */ + private String actNoType; + + @JSONField(serialize = false) + public String getActNo() { + return settAccountNo; + } + + /** + * 使用 settAccountIdcardNo + * 结算人证件号 + * 对私结算必传 + */ + @JSONField(serialize = false) + public String getStmManIdNo() { + if ("Y".equals(authSettle)) { + return settAccountIdcardNo; + } else { + return idcardNo; + } + } + + @JSONField(serialize = false) + public String getAccountLicStt() { + if (Objects.equals(authSettle, "Y")) { + return settAccountIdcardEffectBegin.replace("-", ""); + } else { + return idcardEffectBegin.replace("-", ""); + } + } + + /** + * 结算人证件号到期日 + * 格式为:YYYYMMDD + * 长期有效请传29991231 + */ + @JSONField(serialize = false) + public String getAccountLicEnt() { + if (!Objects.equals(authSettle, "Y")) { + return getLegalPersonLicEnt(); + } else { + Assert.notNull(settAccountIdcardEffectEnd, "结算人证件号到期日不能为空"); + if (settAccountIdcardEffectEnd.equals("长期")) { + return "29991231"; + } + return settAccountIdcardEffectEnd.replace("-", ""); + } + } + + /** + * 使用 settAccountBankName + * 开户银行 + * 如联行行号不传,【开户银行、开户省份、开户城市】即为必传 + */ + @JSONField(serialize = false) + public String getDepoBank() { + return settAccountBankName; + } + + @JSONField(serialize = false) + public String getDepoProvCd() { + if (settAccountBankBranchAreaCode == null || settAccountBankBranchAreaCode.isEmpty()) { + throw new BizException("开户行省市区不能为空"); + } + return settAccountBankBranchAreaCode.getString(0); + } + + @JSONField(serialize = false) + public String getDepoCityCd() { + if (settAccountBankBranchAreaCode == null || settAccountBankBranchAreaCode.size() < 2) { + throw new BizException("开户行市区不能为空"); + } + return settAccountBankBranchAreaCode.getString(1); + } + + +// private String lbnkNo; + + /** + * 使用 settAccountBankBranchCode + * 开户支行联行行号 + * 对公必传,对私非18大行必传;发卡行是村镇银行、城市商业银行、农村商业银行、其他银行则必传 + */ + @JSONField(serialize = false) + public String getLbnkNo() { + return settAccountBankBranchCode; + } + + /** + * 开户支行名称 + */ + @JSONField(serialize = false) + public String getLbnkNm() { + return settAccountBankName; + } + + /** + * 营业执照照片地址, 上传返回的图片短链接 + * 个体、企业、政府机关、事业单位、其他组织必传 + */ + @JSONField(serialize = false) + public String getLicensePic() { + return licenseImg; + } + + /** + * 税务登记证照片地址, 上传返回的图片短链接 + * 企业、政府机关、事业单位、其他组织非三证合一必传 + */ + private String taxRegistLicensePic; + + /** + * 组织机构代码证照片地址 + * 企业、政府机关、事业单位、其他组织非三证合一必传 + */ + private String orgCodePic; + + /** + * 法人/商户负责人身份证正面(人像面)照片地址 + */ + @JSONField(serialize = false) + public String getLegalPersonidPositivePic() { + return idcard1Img; + } + + /** + * 法人/商户负责人身份证反面(国徽面)照片地址 + */ + @JSONField(serialize = false) + public String getLegalPersonidOppositePic() { + return idcard2Img; + } + + /** + * 开户许可证照片地址 + * 对公结算必传 + */ + @JSONField(serialize = false) + public String getOpeningAccountLicensePic() { + return companyAccountLicenseImg; + } + + /** + * 银行卡正面照片地址 + * 对私结算必传 + */ + @JSONField(serialize = false) + public String getBankCardPositivePic() { + return settAccountLicenseImg; + } + + /** + * 银行卡反面照片地址 + */ + private String bankCardOppositePic; + + /** + * 结算人身份证正面(人像面)照片地址 + * 对私授权结算必传 + */ + @JSONField(serialize = false) + public String getSettlePersonIdcardPositive() { + if (Objects.equals("Y", authSettle)) { + return settAccountIdcard1Img; + } else { + return idcard1Img; + } + } + + @JSONField(serialize = false) + public String getSettlePersonIdcardOpposite() { + if (Objects.equals("Y", authSettle)) { + return settAccountIdcard2Img; + } else { + return idcard2Img; + } + } + + /** + * 商户协议照片地址 + */ + private String merchantAgreementPic; + + /** + * 门头照片地址 + */ + @JSONField(serialize = false) + public String getStorePic() { + return storeOuterImg; + } + + /** + * 真实商户内景照片地址 + */ + @JSONField(serialize = false) + public String getInsideScenePic() { + return storeInnerImg; + } + + /** + * 经营场所(含收银台)照片地址 + */ + @JSONField(serialize = false) + public String getBusinessPlacePic() { + return storeCashierImg; + } + + /** + * ICP许可证或公众号主体信息截图照片地址 + * 线上网站类、公众号类商户必传 + * 经营类型为线上(operationalType=='02')时,本字段必填 + */ + private String icpLicence; + + /** + * 手持身份证(人像面)照片地址 + */ + private String handIdcardPic; + + /** + * 租赁协议一(封面)照片地址 + */ + private String leaseAgreementOnePic; + + /** + * 租赁协议二(面积、有效期页)照片地址 + */ + private String leaseAgreementTwoPic; + + /** + * 租赁协议三(签章页)照片地址 + */ + private String leaseAgreementThreePic; + + /** + * 其他资料照片1地址 + * 机构跟银行的合作协议关键页或机构银行合作授权函 (支付宝非盈利时需要上传) + */ + private String otherMaterialPictureOne; + + /** + * 其他资料照片2地址 + * 内景照片(支付宝非盈利时需要上传) + */ + private String otherMaterialPictureTwo; + + /** + * 其他资料照片3地址 + * 财务室照片(支付宝非盈利时需要上传) + */ + private String otherMaterialPictureThree; + + /** + * 其他资料照片4地址 + */ + private String otherMaterialPictureFour; + + /** + * 其他资料照片5地址 + */ + private String otherMaterialPictureFive; + + /** + * 代理人签名照片地址 + */ + private String agentPersonSignature; + + /** + * 确认人签名照片地址 + */ + private String confirmPersonSignature; + + /** + * 授权函照片地址 + * 非法人对私结算,即结算账户类型为对私结算,且结算人身份证号与法人身份证号不一致时该字段必传非法人结算授权函; + * 结算账户类型为对公结算,结算账户名与营业执照注册名称不一致时该字段必传对公结算说明函 + */ + private String letterOfAuthPic; + + /** + * 统一结算无营业执照说明照片地址 + * 个人资质的连锁分店,如果统一结算,需上传总店对该店情况说明、证明连锁关系 + */ + private String unionSettleWithoutLicense; + + /** + * 民办非企业单位登记证书 + * 部分MCC必传,参照 https://paas.tianquetech.com/docs/#/api/shrz + */ + private String privateNonEnterprisePic; + + /** + * 收费样本文件 + * 部分MCC必传,参照 https://paas.tianquetech.com/docs/#/api/shrz + */ + private String feeSimplesPic; + + /** + * 卫生局批文 + * 部分MCC必传,参照 https://paas.tianquetech.com/docs/#/api/shrz + */ + private String healthBureauApprovalPic; + + @Override + public String bankBranchNo() { + return settAccountBankBranchCode; + } + + @Override + public String bankAccountName() { + return settAccountName; + } + + @Override + public void saveCheck() { + super.saveCheck(); + Assert.notNull(settAccountBankBranchCode, "开户支行联行号不能为空"); + } + + @Data + public static class RateInfo { + + /** + * 01 微信贷记卡费率 + * 011微信借记卡费率 + * 012微信借记卡封顶手续费 + * 02 支付宝贷记卡费率 + * 021 支付宝借记卡费率 + * 022 支付宝借记卡封顶手续费 + * 03 翼支付贷记卡费率 + * 031 翼支付借记卡费率 + * 032 翼支付借记卡封顶手续费 + * 06 银联单笔小于1000贷记卡费率 + * 061 银联单笔小于1000借记卡费率 + * 07 银联单笔大于1000贷记卡费率 + * 071 银联单笔大于1000借记卡费率 + * 072 银联单笔大于1000借记卡封顶手续费 + */ + @JSONField(ordinal = 1) + private String rateType; + + @JSONField(ordinal = 2) + private String rate; + + public static final String WX_CREDIT_RATE = "01"; + public static final String WX_DEBIT_RATE = "011"; + public static final String WX_DEBIT_RATE_TOP = "012"; + + public static final String ALI_CREDIT_RATE = "02"; + public static final String ALI_DEBIT_RATE = "021"; + public static final String ALI_DEBIT_RATE_TOP = "022"; + + public static final String YZF_CREDIT_RATE = "03"; + public static final String YZF_DEBIT_RATE = "031"; + public static final String YZF_DEBIT_RATE_TOP = "032"; + + public static final String YSF_CREDIT_RATE_LT_1000 = "06"; + public static final String YSF_DEBIT_RATE_LT_1000 = "061"; + + public static final String YSF_CREDIT_RATE_GT_1000 = "07"; + public static final String YSF_DEBIT_RATE_GT_1000 = "071"; + public static final String YSF_DEBIT_RATE_GT_1000_TOP = "072"; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/TerpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/TerpayApplymentInfo.java new file mode 100644 index 0000000..adc87b1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/TerpayApplymentInfo.java @@ -0,0 +1,183 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; +import java.util.TreeMap; + +@Data +public class TerpayApplymentInfo extends ApplymentBasicInfo { + + /** 手机号 登入账号custLogin(手机号) 必须保持一致 **/ + public String mobileNo; + + /** 经营类型01 门店场所 02流动经营/便民服务 03线上商品/服务交易 **/ + public String manageType; + + /** 开户行(缩写) **/ + public String headBankNo; + + /** 开户支行信息 **/ + public String openBankMsg; + + //******费率信息********** + + + //******其他信息********** + + /** 时间戳 用于同一批次图片上传 **/ + public String timestamp; + + /** 补充材料3 (手持结算卡照片) 结算类型为非法人时必传 **/ + public String filed3; + public String filed2; + public String filed5; + + /** 结算姓名 **/ + public String stlName; + /** 非法人对私上传的授权书 结算类型为非法人时必传 **/ + public String stlAuth; + /** 结算人站门头照 **/ + public String stlDoor; + /** 非法人授权结算书 **/ + public String authCert; + + + + /** 验证码(需要签署安心签才需传) **/ + public String checkCode; + + /** 是否走第一次进件 目的:安心签签署失败可以不用放弃当前申请单 **/ + public String ifFirstApply; + + + + /** + * merchantType: 1-个人 2-个体 3-企业 + * 1:个体工商户(普通) 2:企业(普通)3:小微 + * 商户类型转换 00:小微 ,01 普通(主体类型 1个体工商户 2企业 3政府及事业单位 5其他机构组织) + */ + public String coverMerchantType() { + Byte merchantType = this.merchantType; + String merType = ""; + switch (merchantType) { + case 1: { + merType = "3"; + break; + } + case 2: { + merType = "1"; + break; + } + case 3: { + merType = "2"; + break; + } + default: + merType = "3"; + } + return merType; + } + + /** 结算账户类型 01 对公 02法人对私 03非法人对私**/ + public String convertAccountType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "01"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "02"; + }else if ("C2".equals(this.getSettAccountType())) { + return "03"; + } + return ""; + } + + // 有效期转换 + public String coverDateTime(String dateStr) { + if ("长期".equals(dateStr)) { + return "长期"; + } else { + return dateStr.replace("-", ""); + } + } + + // 开户支行信息转换 例:四平市古城农村信用合作社_401243301421 + public String[] coverBranchBankMsg(String openBankMsg) { + if (StringUtils.isEmpty(openBankMsg)) { + return null; + } else { + return openBankMsg.split("_"); + } + } + + public void convertApplymentPayFee(TreeMap paperJson) { + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + // 费率 【以下费率配置以星驿付机构配置】 新机构不一致情况 可按机构类型区分 + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + paperJson.put("rateWx", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + paperJson.put("rateZfb", convertRate(item.getFeeRate()) + ""); + } + + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为% + paperJson.put("rateYlCap0", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记卡优惠类结算费率 + paperJson.put("ratePosJy", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + paperJson.put("rateYlCap1", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记卡标准类结算费率(%) + paperJson.put("ratePosJb", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记卡优惠类消费封顶值(分) + paperJson.put("moneyPosJy", item.getMaxFee().toString() + ""); + // 借记卡标准类消费封顶值(分) + paperJson.put("moneyPosJb", item.getMaxFee().toString() + ""); + + } + // 贷记卡费率 + if (item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())) { + // 贷记卡手续费费率(单笔交易<1000元) 参数单位为‰ + paperJson.put("rateYlRat0", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + // 贷记卡优惠类结算费率(%) + paperJson.put("ratePosDy", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + paperJson.put("rateYlRat1", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + // 贷记卡标准类结算费率(%) + paperJson.put("ratePosDb", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + } + } + }); + } + } + + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + String[] strings = coverBranchBankMsg(openBankMsg); + if (strings == null) { + return null; + } else { + return strings[1]; + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmhspayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmhspayApplymentInfo.java new file mode 100644 index 0000000..7174828 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmhspayApplymentInfo.java @@ -0,0 +1,151 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +@Data +public class UmhspayApplymentInfo extends ApplymentBasicInfo { + /** 商户手机号(商户登陆账号)唯一,不能重复 **/ + private String accountPhone; + + /** 店铺类型 1-主店;2-独立结算分店;3-合并结算分店;4-分账接收方 **/ + private Byte shopType; + + /** 总店商户号 **/ + private String shopMerchantId; + + /** 总-门店关系说明函(图片id),总分店同个营业执照必填 **/ + private String relationCertPic; + + /** 联系人类型:0-法人;1-委托人; **/ + private Byte contactType; + + /** 银行预留手机号 **/ + private String prePhone; + + /** 开户支行联行号 **/ + private String openBankCode; + + /* 分账相关所需上送内容 start ------------------------------------------------- **/ + /** 三方协议形式:1-纸质协议;2-电子协议 **/ + private Byte contractType; + /** 商户收单主协议,传<图片上传>返回的对应file_id,格式为[1,2,3] 若该主商户历史有过成功的关联记录,或者三方协议形式为电签则可以不传; **/ + private String agrmPic; + /** 三方分账授权协议,传<图片上传>返回的对应file_id,格式为[1,2,3] 如电签则不需要上传 **/ + private String shareAgrmPic; + /** 商户分账服务开通申请登记表 格式为[1,2,3] **/ + private String supmtAgrmPic; + /** 分账方和分账接收方之间的业务合作协议 格式为[1,2,3] **/ + private String copAgrmPic; + + /** 分账电签:商户签约人类型 **/ + private String merSignType; + /** 分账电签:商户签约人手机号码 **/ + private String merSignPhone; + /** 分账电签:商户经办人身份证人像面照片 **/ + private String merCardHeadsPic; + /** 分账电签:商户经办人身份证国徽面照片 **/ + private String merCardTailsPic; + /** 分账电签:商户经办人电签授权书 **/ + private String merContractAuth; + /** 分账电签:商户签约人姓名 **/ + private String merSignName; + /** 分账电签:商户签约人身份证号 **/ + private String merSignCard; + + /* 分账相关所需上送内容 end ------------------------------------------------- **/ + + + /** 结算账户类型 1-法人对私;2-非法人对私;3-法人对公;merchantType=1-小微,该参数必须为1-法人对私 **/ + public String convertAccountType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "1"; + }else if ("C2".equals(this.getSettAccountType())) { + return "2"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "3"; + } + return "1"; + } + + /** 费率相关业务信息 **/ + public JSONArray convertApplymentPayFee() { + // 微信业务申请信息 + JSONObject wxJson = new JSONObject(); + // 支付宝业务申请信息 + JSONObject aliJson = new JSONObject(); + // 云闪付1000以下(包含1000) + JSONObject litYsfJson = new JSONObject(); + // 云闪付1000以上(不包含1000) + JSONObject bigYsfJson = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + wxJson.put("transType", 1); + wxJson.put("merchantDefaultD1Rate", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + aliJson.put("transType", 2); + aliJson.put("merchantDefaultD1Rate", convertRate(item.getFeeRate()) + ""); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if (CollUtil.isNotEmpty(item.getLevelList())) { + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 云闪付1000以下(包含1000) + litYsfJson.put("transType", 3); + // 商户签约费率(交易费率),单位:% + litYsfJson.put("merchantDefaultD1Rate", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + + // 云闪付1000以上(不包含1000) + bigYsfJson.put("transType", 4); + // 商户签约费率(交易费率),单位:% + bigYsfJson.put("merchantDefaultD1Rate", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + } + } + }); + } + + JSONArray merchantFeeRateList = new JSONArray(); + if (!wxJson.isEmpty()){ + merchantFeeRateList.add(wxJson); + } + if (!aliJson.isEmpty()){ + merchantFeeRateList.add(aliJson); + } + if (!litYsfJson.isEmpty()){ + merchantFeeRateList.add(litYsfJson); + } + if (!bigYsfJson.isEmpty()){ + merchantFeeRateList.add(bigYsfJson); + } + + return merchantFeeRateList; + } + + + public static String convertRate(BigDecimal rate) { + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + @Override + public String bankBranchNo() { + return openBankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmpayApplymentInfo.java new file mode 100644 index 0000000..238e990 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UmpayApplymentInfo.java @@ -0,0 +1,126 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.List; + +@Data +public class UmpayApplymentInfo extends ApplymentBasicInfo{ + + /** 客服电话 **/ + private String servicePhone; + + /** 座机电话 **/ + private String merchantPhone; + + /** 执照证件类型 NATIONAL_LEGAL-营业执照 NATIONAL_LEGAL_MERGE-多证合一 **/ + private String licenseType; + + /** 0-非法人 1-法人 2-单位 **/ + private String cardType; + + /** 非法人清算授权函 **/ + private String certificatePic; + + /** 开户行联行行号 **/ + private String unitedBankNo; + + /** 商户特殊行业资质证明 **/ + private String qualificationImg; + + /** 商户特殊行业资质证明 **/ + private String elseImg; + + /** 商户经营类型 MICRO_TYPE_STORE-门店 MICRO_TYPE_MOBILE-流动经营/便民服务 MICRO_TYPE_ONLINE-线上商品/服务交易 **/ + private String microBizType; + + /** 注册资金 **/ + private String capital; + + + /** 商户名称转换 **/ + public String convertMerchantName() { + if (MchApplyment.MERCHANT_TYPE_PERSONAL == this.merchantType) { + // 小微商户名称:商户_+法人姓名 + return "商户_" + this.getIdcardName(); + }else { + // 商户全称 + return this.mchFullName; + } + } + + /** 结算账户类型 **/ + public String convertSettType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + // 对公 + return "1"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + // 对私 + return "0"; + } + return ""; + } + + public String convertDate(String dateStr) { + if ("长期".equals(dateStr)) { + return "9999-12-31"; + } + return dateStr; + } + + /** 支付产品 **/ + public JSONObject convertProduct() { + JSONObject feeJson = new JSONObject(); + List paywayFeeList = this.paywayFeeList; + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + paywayFeeList.stream().forEach(item -> { + // 阶梯费率 + if ((item.getWayCode().startsWith("YSF_") || item.getWayCode().startsWith("UP_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + feeJson.put("unionOpen", "1"); + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 借记手续费 1000以下费率 + feeJson.put("unionDebitRate", item.getLevelList().get(0).getFeeRate() + ""); + // 借记手续费 1000以上费率 + feeJson.put("unionUpDebitRate", item.getLevelList().get(1).getFeeRate() + ""); + // 借记封顶 + feeJson.put("unionDebitLimit", AmountUtil.convertCent2Dollar(item.getMaxFee())); + feeJson.put("unionUpDebitLimit", AmountUtil.convertCent2Dollar(item.getMaxFee())); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + // 1000以下费率 + feeJson.put("unionCreditRate", item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate() + ""); + // 1000以上费率 + feeJson.put("unionUpCreditRate", item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate() + ""); + } + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + feeJson.put("aliMerchantRate", item.getFeeRate()); + } + + // 微信费率 + if (item.getWayCode().startsWith("WX_") && PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + feeJson.put("wxMerchantRate", item.getFeeRate()); + } + + }); + } + return feeJson; + } + + + @Override + public String bankBranchNo() { + return unitedBankNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UtmpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UtmpayApplymentInfo.java new file mode 100644 index 0000000..da42090 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/UtmpayApplymentInfo.java @@ -0,0 +1,168 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.model.params.utmpay.UtmpayConfig; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.*; + +@Data +public class UtmpayApplymentInfo extends ApplymentBasicInfo{ + + /** 客服电话 **/ + public String customerPhone; + + /** 企业法人【姓名】 **/ + public String legalPerson; + + /** 执照类型 00-统一社会信用代码证号(三证合一) 01-营业执照(非三证合一) 02-其他 **/ + public String businessLicenseType; + + /** 银行预留手机号 **/ + public String bankCardPhone; + + /** 结算信息 是否为负责人信息 **/ + public String isContactInfo; + + /** 联行行号 **/ + public String contactLine; + + /** 开户银行ID **/ + public String bankId; + + /** 商户协议照片1 **/ + public String protocolPhoto1; + + /** 商户协议照片2 **/ + public String protocolPhoto2; + + /** 商户协议照片3 **/ + public String protocolPhoto3; + + /** 商户协议照片4 **/ + public String protocolPhoto4; + + /** 组织机构代码证照片 **/ + public String orgPhoto; + + /** 其他资料照片 **/ + public String otherDoc; + + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertMerchantType(){ + + if(this.merchantType == null){ + return ""; + } + + if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "1"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "2"; + } + return ""; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertAccountType(){ + if(StringUtils.isBlank(this.settAccountType)){ + return ""; + } + + if(this.settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE)) { + return "1"; + }else if(this.settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL)) { + return "2"; + } + return ""; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public static List> convertPaywayFeeList(List paywayFeeList){ + + // 签约产品不存在 && 不包含分账产品 + if(paywayFeeList == null) { + return null; + } + + List> result = new LinkedList<>(); + + // 签约收单产品 集合 + for (PaywayFee paywayFee : paywayFeeList) { + + SortedMap mchPayConf = new TreeMap<>(); + + // 第一步: + // 支付类型(暂时写死), + // 实际取值请联系技术支持获取,每个行不一样。可以通过管理平台"机构管理"->"机构进件管理"页面上的“机构支付类型配置信息”中查看。 + // 文档地址:https://up.95516.com/open/openapi/doc?index_1=127&index_2=1&chapter_1=1943&chapter_2=1945 + String payTypeId = UtmpayConfig.yplPayWayMap.get(paywayFee.getWayCode()); + + // 不存在该支付类型 + if(StringUtils.isEmpty(payTypeId)){ + continue; + } + + // 支付类型 + mchPayConf.put("wayCode", paywayFee.getWayCode()); + mchPayConf.put("payTypeId", payTypeId); + + // 单笔费率 + if(PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())){ + mchPayConf.put("billRate", convertRate(paywayFee.getFeeRate())); + + result.add(mchPayConf); + continue; + } + + // 以下为银联阶梯费率 + if(Arrays.asList(CS.PAY_WAY_CODE.UP_BAR, CS.PAY_WAY_CODE.UP_JSAPI, CS.PAY_WAY_CODE.UP_QR, CS.PAY_WAY_CODE.YSF_BAR, CS.PAY_WAY_CODE.YSF_JSAPI) + .contains(paywayFee.getWayCode())){ + + // 借记卡费率 + if(CollUtil.isNotEmpty(paywayFee.getLevelList())){ + mchPayConf.put("billRate1",convertRate(paywayFee.getLevelList().get(0).getFeeRate())); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + mchPayConf.put("billRate3",convertRate(paywayFee.getLevelList().get(1).getFeeRate())); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + mchPayConf.put("debitCardBrokerageLimitBd", convertFee(paywayFee.getMaxFee())); // 借记卡手续费封顶 单位:元 + } + + // 信用卡费率 + if(paywayFee.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(paywayFee.getCreditCardPaywayFee().getLevelList())){ + mchPayConf.put("billRate",convertRate(paywayFee.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())); // 信用卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + mchPayConf.put("billRate2",convertRate(paywayFee.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); // 信用卡手续费费率(单笔交易>1000元) 参数单位为‰ + } + + } + + result.add(mchPayConf); + + } + + return result; + + } + + private static String convertRate(BigDecimal rate){ + return rate == null ? null : rate.multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(); + } + + private static String convertFee(Long fee){ + + if(fee == null){ + return null; + } + + return AmountUtil.convertCent2Dollar(fee); + } + + @Override + public String bankBranchNo() { + return contactLine; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/VbillpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/VbillpayApplymentInfo.java new file mode 100644 index 0000000..3aef090 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/VbillpayApplymentInfo.java @@ -0,0 +1,270 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.utils.AmountUtil; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; + +@Data +public class VbillpayApplymentInfo extends ApplymentBasicInfo{ + + /** 经营类型:01-线下 02-线上 */ + private String operationalType; + + /** 线上产品类型:01-APP 02-网站 03-公众号/小程序/服务窗 */ + private String onlineType; + + /** APP名称/网站网址/公众号/小程序/服务窗名称 */ + private String onlineName; + + /** 营业执照注册名称 */ + private String cprRegNmCn; + + /** 是否三证合一 :00-是 01-否 */ + private String licenseMatch; + + /** 组织机构代码证照片 */ + private String orgCodePic; + + /** 组织机构代码 */ + private String orgCode; + + /** 税务登记证照片 */ + private String taxRegistLicensePic; + + /** 税务登记号 */ + private String taxRegNo; + + /** 结算类型:03-T1结算 04-D1结算 */ + private String settleType; + + /** 联行号 */ + private String branchCode; + + /** ICP许可证或公众号主体信息截图照片地址 */ + private String icpLicence; + + /** 授权函照片地址 */ + private String letterOfAuthPic; + + /** 结算账户性质 1-法人 2-非法人 **/ + public Byte accountNature; + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertMerchantType(){ + + if(this.merchantType == null){ + return null; + } + + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "01"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "02"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "03"; + } + return ""; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertLicenseEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.licenseEffectEnd) ? "29991231" : formatVbillDate(this.licenseEffectEnd); // 盛付通 长期需要传入: 2199-12-31 + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertIdcardEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.idcardEffectEnd) ? "29991231" : formatVbillDate(this.idcardEffectEnd); // 盛付通 长期需要传入: 2199-12-31 + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertSettAccountIdcardEffectEnd(){ + return DATE_FOREVER_VAL.equals(this.settAccountIdcardEffectEnd) ? "29991231" : formatVbillDate(this.settAccountIdcardEffectEnd); // 盛付通 长期需要传入: 2199-12-31 + } + + /** 类型转换:结算账户类型 **/ + public String covertSettAccountType() { + if(StringUtils.isBlank(this.settAccountType)){ + return null; + } + + if(this.settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL)){ + return "01"; + }else if(this.settAccountType.equals(MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE)){ + return "00"; + } + return ""; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public List convertQrCodeList(){ + + // 费率不存在 + if(this.paywayFeeList == null){ + return null; + } + + // 二维码费率(%) + List qrcodeList = new ArrayList<>(); + + // 签约收单产品 集合 + for (PaywayFee paywayFee : this.paywayFeeList) { + + JSONObject qrcodeRateJSON = new JSONObject(); // 二维码费率 + + // 二维码费率: + // 01 微信费率 + // 02 支付宝费率 + // 06 银联单笔小于等于1000费率 + // 07 银联单笔大于1000费率 + + // 微信、支付宝 单笔费率 + if(PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())){ + if (paywayFee.getWayCode().startsWith("WX_")) { + + // 去重,否则接口会报错 + if (qrcodeList.stream().anyMatch(item -> "01".equals(item.getString("rateType")))) { + continue; + } + + qrcodeRateJSON.put("rateType", "01"); + qrcodeRateJSON.put("rate", convertRate(paywayFee.getFeeRate())); + qrcodeList.add(qrcodeRateJSON); + + }else if (paywayFee.getWayCode().startsWith("ALI_")) { + + // 去重,否则接口会报错 + if (qrcodeList.stream().anyMatch(item -> "02".equals(item.getString("rateType")))) { + continue; + } + + qrcodeRateJSON.put("rateType", "02"); + qrcodeRateJSON.put("rate", convertRate(paywayFee.getFeeRate())); + qrcodeList.add(qrcodeRateJSON); + + } + } + // 银联阶梯费率 + else if (PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) && paywayFee.getWayCode().startsWith("UP_")) { + + // 借记卡 + List levelList = paywayFee.getLevelList(); + if(levelList == null && paywayFee.getCreditCardPaywayFee() != null){ + levelList = paywayFee.getCreditCardPaywayFee().getLevelList(); + } + if (CollUtil.isEmpty(levelList) || levelList.size() != 2) { + throw new BizException("请配置银联阶梯费率!"); + } + + // 去重,否则接口会报错 + if (qrcodeList.stream().anyMatch(item -> "06".equals(item.getString("rateType")) || "07".equals(item.getString("rateType")))) { + continue; + } + PaywayFee feeItem = levelList.get(0); + JSONObject qrcodeRate = new JSONObject(); // 二维码费率 + qrcodeRate.put("rateType", "06"); + qrcodeRate.put("rate", convertRate(feeItem.getFeeRate())); + qrcodeList.add(qrcodeRate); + + PaywayFee feeItem1 = levelList.get(1); + JSONObject qrcodeRate2 = new JSONObject(); // 二维码费率 + qrcodeRate2.put("rateType", "07"); + qrcodeRate2.put("rate", convertRate(feeItem1.getFeeRate())); + qrcodeList.add(qrcodeRate2); + + } + } + + return qrcodeList; + } + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public List convertBankCardRates() { + // 费率不存在 + if(this.paywayFeeList == null){ + return null; + } + + // 刷卡费率(%) + List bankCardRates = new ArrayList<>(); + + // 费率集合 + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 刷卡费率: + // 21 贷记卡费率,不传默认0.60 + // 22 借记卡费率,不传默认0.55 + // 23 借记卡手续费封顶值,不传默认25 + // 24 云闪付贷记卡费率,不传默认银联二维码1000以上贷记卡费率 + // 25 云闪付的借记卡费率,不传默认银联二维码1000以上贷记卡费率 + + // 银联阶梯费率 + if (PaywayFee.FEE_TYPE_LEVEL.equals(paywayFee.getFeeType()) && paywayFee.getWayCode().startsWith("UP_")) { + + // 借记卡 + List levelList = paywayFee.getLevelList(); + if (CollUtil.isNotEmpty(levelList)) { + for (PaywayFee feeItem : levelList) { + // 去重,否则接口会报错 + if (bankCardRates.stream().anyMatch(item -> "22".equals(item.getString("type")))) { + continue; + } + + JSONObject bankCardRate = new JSONObject(); // 刷卡费率 + bankCardRate.put("type", "22"); + bankCardRate.put("rate", convertRate(feeItem.getFeeRate())); + bankCardRates.add(bankCardRate); + + JSONObject bankCardRate2 = new JSONObject(); // 刷卡费率 + bankCardRate2.put("type", "23"); + bankCardRate2.put("rate", AmountUtil.convertCent2Dollar(paywayFee.getMaxFee())); + bankCardRates.add(bankCardRate2); + } + } + + if(paywayFee.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(paywayFee.getCreditCardPaywayFee().getLevelList())){ + for (PaywayFee feeItem : paywayFee.getCreditCardPaywayFee().getLevelList()) { + // 去重,否则接口会报错 + if (bankCardRates.stream().anyMatch(item -> "21".equals(item.getString("type")))) { + continue; + } + + JSONObject bankCardRate = new JSONObject(); // 刷卡费率 + bankCardRate.put("type", "21"); + bankCardRate.put("rate", convertRate(feeItem.getFeeRate())); + bankCardRates.add(bankCardRate); + } + } + } + } + + return bankCardRates; + } + + /** 费率转换 */ + private String convertRate(BigDecimal rate){ + return rate == null ? null : rate.multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP).toString(); + } + + /** 日期转换,去掉横线 */ + public String formatVbillDate(String date) { + if (StringUtils.isBlank(date)) { + return null; + } + + return date.replaceAll("-", ""); + } + + @Override + public String bankBranchNo() { + return branchCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/WxpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/WxpayApplymentInfo.java new file mode 100644 index 0000000..8f210f2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/WxpayApplymentInfo.java @@ -0,0 +1,87 @@ +package com.jeequan.jeepay.core.model.applyment; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class WxpayApplymentInfo extends ApplymentBasicInfo{ + + /** 超级管理员类型:LEGAL:经营者/法人,SUPER:经办人 */ + protected String contactType; + + /** 超级管理员身份证件号码 */ + protected String contactIdNumber; + + /** 超管身份证人像面照片 */ + protected String contactIdDocCopy; + + /** 超管身份证国徽面照片 */ + protected String contactIdDocCopyBack; + + /** 超管身份证起始有效期 */ + protected String contactIdDocPeriodBegin; + + /** 超管身份证结束有效期 */ + protected String contactIdDocPeriodEnd; + + /** 业务办理授权函 */ + protected String businessAuthorizationLetter; + + /** 经营场景类型 线下门店:SALES_SCENES_STORE */ + protected String salesSceneType; + + /** 门店名称 */ + protected String storeName; + + /** 入驻结算规则ID */ + protected String settlementId; + + /** 行业ID */ + protected String qualificationId; + + /** 是否需要上传特殊资质 */ + protected Boolean isNeedQualification; + + /** 特殊资质 */ + protected String qualifications; + + /** 客服电话 */ + protected String servicePhone; + + /** 是否参与优惠费率活动 */ + protected String isInActivities; + + /** 优惠费率活动ID */ + protected String activitiesId; + + /** 法人是否为受益人 */ + protected Boolean owner; + + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertPaywayFeeList2String(){ + + if(this.paywayFeeList == null){ + return null; + } + + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 单笔费率配置 + if (PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())) { + return convertRate(paywayFee.getFeeRate()); + } + } + return null; + } + + private String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YsfpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YsfpayApplymentInfo.java new file mode 100644 index 0000000..14a369f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YsfpayApplymentInfo.java @@ -0,0 +1,214 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class YsfpayApplymentInfo extends ApplymentBasicInfo{ + + /** 门店外景照 **/ + public String storeOuter2Img; + + /** 客服电话 **/ + public String serviceTel; + + /** 结算账户类型 1-对公 2-法人账户 3-授权人账户 **/ + public String settleAccountType; + + /** 结算周期 1-T+1 2-D+0 3-T+0 4-D+1 **/ + public String settlePeriod; + + /** 开户行联行号 **/ + public String openBankCode; + + /** 银行预留手机号 **/ + public String openBankReservePhone; + + /** 商户收单协议照 **/ + public String acquiringAgreementPhoto; + + /** 结算授权照 **/ + public String settleAuthLetterPhoto; + + /** 拓展材料 **/ + public String reserve1; + + /** 机构类型 **/ + public String acqOrgType; + + // 商户类型转换 + public String coverMerchantType() { + Byte merchantType = this.merchantType; + String merType = ""; + switch (merchantType) { + case 1:{ + merType = "3"; + break; + } + case 2:{ + merType = "1"; + break; + } + case 3:{ + merType = "2"; + break; + } + } + return merType; + } + + // mcc转换 + public String coverMcc() { + String[] mccCodeArr = this.mccCode.split("_"); + return mccCodeArr[1]; + } + + // 有效期转换 + public String coverDateTime(String dateStr) { + if ("长期".equals(dateStr)) { + return dateStr; + }else { + return dateStr.replace("-",""); + } + } + + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public JSONObject convertPaywayFeeList(){ + + if(this.paywayFeeList == null){ + return null; + } + + JSONObject result = new JSONObject(); + + for (PaywayFee paywayFee : this.paywayFeeList) { + + // 第一步: 转换产品ID ( 本系统 --》 云闪付 ) + String bizProductCode = null; + switch (paywayFee.getWayCode()){ + case CS.PAY_WAY_CODE.WX_BAR: bizProductCode = "feeRateWechatpay"; break; + case CS.PAY_WAY_CODE.WX_JSAPI: bizProductCode = "feeRateWechatpay"; break; + case CS.PAY_WAY_CODE.WX_H5: bizProductCode = "feeRateWechatpay"; break; + case CS.PAY_WAY_CODE.WX_LITE: bizProductCode = "feeRateWechatpay"; break; + case CS.PAY_WAY_CODE.WX_NATIVE: bizProductCode = "feeRateWechatpay"; break; + case CS.PAY_WAY_CODE.ALI_BAR: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.ALI_JSAPI: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.ALI_LITE: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.ALI_PC: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.ALI_QR: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.ALI_WAP: bizProductCode = "feeRateAlipay"; break; + case CS.PAY_WAY_CODE.YSF_BAR: bizProductCode = "rateConfig"; break; + } + // 云闪付不存在该产品 + if(StringUtils.isEmpty(bizProductCode)){ + continue; + } + + // 云闪付费率 + if ("rateConfig".equals(bizProductCode)) { + // 金额大于1000以上的费率 + JSONObject level1Json = new JSONObject(); + // 银联借记卡费率 + level1Json.put("feeRateUnionpayDebit", convertRate(paywayFee.getFeeRate())); + // 借记卡封顶 0不封顶 瑞银信 18-80 + level1Json.put("feeRateUnionpayDebitCap", "8000"); + level1Json.put("feeRateUnionpayCredit", convertRate(paywayFee.getFeeRate())); + result.put("bankCardRateLevel1", level1Json); + // 金额小于1000以下的费率 + result.put("bankCardRateLevel2", level1Json); + continue; + } + + // 支付宝、微信 单笔费率 + if(PaywayFee.FEE_TYPE_SINGLE.equals(paywayFee.getFeeType())){ + // 产品编码 + result.put(bizProductCode, convertRate(paywayFee.getFeeRate())); + continue; + } + + } + return result; + + } + + public JSONObject convertApplymentPayFee() { + List paywayFeeList = this.paywayFeeList; + JSONObject feeJson = new JSONObject(); + // 费率设置列表 + if (paywayFeeList != null && CollectionUtils.isNotEmpty(paywayFeeList)) { + // 费率 【以下费率配置以瑞银信机构配置】 新机构不一致情况 可按机构类型区分 + paywayFeeList.stream().forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + feeJson.put("feeRateWechatpay", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + feeJson.put("feeRateAlipay", convertRate(item.getFeeRate()) + ""); + } + } + + // 阶梯费率 + if (item.getWayCode().startsWith("YSF_") && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + //银行卡费率一档,交易金额大于 1000 元的费率 + JSONObject bankCardRateLevel1 = new JSONObject(); + //银行卡费率二档,交易金额小于 1000 元的费率 + JSONObject bankCardRateLevel2 = new JSONObject(); + + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + // 借记手续费 + bankCardRateLevel2.put("feeRateUnionpayDebit", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); + // 借记封顶 分 + bankCardRateLevel2.put("feeRateUnionpayDebitCap", "0"); + + // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + // 借记手续费 + bankCardRateLevel1.put("feeRateUnionpayDebit", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); + // 借记封顶 分 + bankCardRateLevel1.put("feeRateUnionpayDebitCap", item.getMaxFee()+""); + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + // 贷记卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + bankCardRateLevel2.put("feeRateUnionpayCredit", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); + + // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bankCardRateLevel1.put("feeRateUnionpayCredit", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); + } + + feeJson.put("bankCardRateLevel1", bankCardRateLevel1); + feeJson.put("bankCardRateLevel2", bankCardRateLevel2); + } + + }); + } + return feeJson; + } + + + public static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP)); + } + + public static void main(String[] args) { + + System.out.println(convertRate(new BigDecimal("0.0028"))); + } + + @Override + public String bankBranchNo() { + return openBankCode; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YspayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YspayApplymentInfo.java new file mode 100644 index 0000000..0206ed0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/YspayApplymentInfo.java @@ -0,0 +1,556 @@ +package com.jeequan.jeepay.core.model.applyment; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; +import java.util.TreeSet; + +@Data +@EqualsAndHashCode(callSuper = true) +public class YspayApplymentInfo extends ApplymentBasicInfo { + + /** 控制人是否同法人 **/ + protected String isControlToLegal; + /** 实际控制人姓名 **/ + protected String controlName; + /** 实际控制人证件号 **/ + protected String controlCertNo; + /** 实际控制人证件起始日期,格式:YYYYMMDD **/ + protected String controlCertBgn; + /** 实际控制人证件有效期,格式:YYYYMMDD **/ + protected String controlCertExpire; + /** 实际控制人证件地址 **/ + protected String controlAddr; + + + /** 是否非法人结算 Y是 N否,默认否 */ + protected String isUncrpSett; + /** 自定义结算账户名 */ + protected String diySettAccountName; + /** 银行预留手机号,非法人结算必填 */ + protected String bankMobile; + /** 开户证件号,默认法人证件号,非法人结算必填 */ + protected String openCertNo; + /** 结算非法人地址 **/ + protected String settleAuthAddress; + /** 结算授权照片,非法人结算必填 **/ + protected String settleAuthLetterPhoto; + /** 法人手持结算授权书,非法人结算必填 **/ + protected String settleAuthLetterHandlePhoto; + + /** 是否提供备用结算账户信息 */ + protected String isOtherAccountInfo; + /** 备用结算账户类型,11 对私 21 对公 23 对公存折 24 单位结算卡 **/ + protected String standByStlAccType; + /** 备用结算账号 **/ + protected String standByStlAccNo; + /** 备用结算户名 **/ + protected String standByStlAccNm; + /** 备用结算账户开户行支行编号 **/ + protected String standByBankSubCode; + + protected String standByAccountBankName; + /** 备用账户结算银行开户支行区域编码 **/ + protected JSONArray standByAccountBankBranchAreaCode; + /** 备用结算账户卡号面 **/ + protected String standByStlAccCardImg; + + + /** 客户经理名称 **/ + protected String cusMgrNm; + + + /** 法人电话号 **/ + protected String legalPersonPhone; + + /** 行别编号 **/ + protected String bankType; + + /** 最低结算金额 **/ + protected BigDecimal lowestStlAmt; + + /** 开户行行号 **/ + protected String openAccBanktype; + + /** 开户支行联行号 **/ + protected String bankSubCode; + + /** 是否为法人结算 0-否 1-是 **/ + protected String codeLegalPersonAcc; + + /** 结算非法人姓名 **/ + protected String unincorporatedName; + + /** 是否为法人信息 **/ + protected String isLegalInfo; + + /** 开户行省 **/ + protected String openAccProvince; + + /** 开户行市 **/ + protected String openAccCity; + + /** 商户归属省 **/ + protected String mercProv; + + /** 商户归属市 **/ + protected String mercCity; + + /** 商户归属区 **/ + protected String mercArea; + + /** 结算卡反面照 **/ + protected String settAccountBankImg2; + + /** 收单协议盖章页照片 **/ + protected String acquiringAgreementPhoto; + + /** 其他材料照片1 **/ + protected String other1; + + /** 结算方式 1- T1/D1 2-D0 */ + protected String settAccountCut; + + /** + * 商户类型 + */ + @JSONField(serialize = false) + public String getYsMerchantType() { + if (this.merchantType == 1) { // 个人 + return "2"; + }else if (this.merchantType == 2) { // 个体工商 + return "3"; + }else if (this.merchantType == 3) { // 企业 + return "4"; + } + return null; + } + + @JSONField(serialize = false) + public boolean isPersonal(){ + // 个人 + return this.merchantType == 1; + } + + /** 结算账户类型,11 对私 21 对公 23 对公存折 24 单位结算卡 **/ + @JSONField(serialize = false) + public String getYsSettAccountType(String settAccountType){ + if ("B".equals(settAccountType)) { + // 对公 + return "21"; + }else if ("B2".equals(settAccountType)) { + // 对公存折 + return "23"; + } else if ("C".equals(settAccountType)) { + // 对私 + return "11"; + } else if ("D".equals(settAccountType)) { + // 单位结算卡 + return "24"; + } + return null; + } + + public String convertDate(String dateStr) { + if ("长期".equals(dateStr)) { + return "29991231"; + }else { + dateStr = dateStr.replace("-", ""); + } + return dateStr; + } + + /** + * 合同签约申请的 费率配置参数 + * 结算方式 settType 1- T1/D1 2-D0 + */ + public static JSONObject convertFeeJSON(List paywayFeeList, String settType) { + + if (CollUtil.isEmpty(paywayFeeList)) { + throw new BizException("请配置费率"); + } + + // D0 + if (settType.contains("3")) { + return paywayFeeList.stream().filter(r -> CS.PAY_WAY_CODE.D0.equals(r.getWayCode())) + .map(r -> { + // 取D1结算费率 + JSONObject rateJSON = new JSONObject(); + rateJSON.put("rateType", "0"); // 默认为百分比费率 + rateJSON.put("rateFee", convertRate(r.getFeeRate())); // 费率值 + rateJSON.put("rateBottom", "1"); // 默认封底金额 + return rateJSON; + }).findFirst().orElseThrow(() -> new BizException("未配置D0手续费费率")); + } + + // D1 + else if (settType.equals("2")) { + return paywayFeeList.stream().filter(r -> CS.PAY_WAY_CODE.D1.equals(r.getWayCode())) + .map(r -> { + // 取D1结算费率 + JSONObject rateJSON = new JSONObject(); + rateJSON.put("rateType", "0"); // 默认为百分比费率 + rateJSON.put("rateFee", convertRate(r.getFeeRate())); // 费率值 + rateJSON.put("rateBottom", "1"); // 默认封底金额 + return rateJSON; + }).findFirst().orElseGet(() -> { + // 取D1结算费率 + JSONObject d1FeeJSON = new JSONObject(); + d1FeeJSON.put("rateType", "0"); // 默认为百分比费率 + // 基本的D1费率值 + d1FeeJSON.put("rateFee", "0.01"); // 费率值 + d1FeeJSON.put("rateBottom", "1"); // 默认封底金额 + return d1FeeJSON; + }); + } + + // T1 + else if (settType.equals("1")) { + return genCodeScanT1FeeJSON(paywayFeeList); + } + + return new JSONObject(); + } + + + + // 扫码工作日到账费率 + private static JSONObject genCodeScanT1FeeJSON(List paywayFeeList) { + JSONObject codeScanT1FeeJSON = new JSONObject(); + + JSONObject wxPayFeeJson = new JSONObject(); // 微信费率 + JSONObject aliPayFeeJson = new JSONObject(); // 支付宝费率 + JSONObject bank1debitFeeJson = new JSONObject(); // 银联一档借记卡扫码费率(>1000) + JSONObject bank2debitFeeJson = new JSONObject(); // 银联二档借记卡扫码费率(<=1000) + JSONObject bank1creditFeeJson = new JSONObject(); // 银联一档贷记卡扫码费率(>1000) + JSONObject bank2creditFeeJson = new JSONObject(); // 银联二档贷记卡扫码费率(<=1000) + + // 费率设置列表 + for (PaywayFee item : paywayFeeList) { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + if (item.getWayCode().startsWith("WX_")) { + wxPayFeeJson.put("rateType", "0"); // 默认为百分比费率 + wxPayFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 费率值 + wxPayFeeJson.put("rateBottom", "1"); // 默认封底金额 + } + + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + aliPayFeeJson.put("rateType", "0"); // 默认为百分比费率 + aliPayFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 费率值 + aliPayFeeJson.put("rateBottom", "1"); // 默认封底金额 + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("UP_") || item.getWayCode().startsWith("YSF_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + // 银联二档借记卡扫码费率(<=1000) + bank2debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2debitFeeJson.put("rateFee", convertRate(item.getLevelList().get(0).getFeeRate())); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + bank2debitFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank2debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶 单位:分 + + // 银联一档借记卡扫码费率(>1000) + bank1debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1debitFeeJson.put("rateFee", convertRate(item.getLevelList().get(1).getFeeRate())); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1debitFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank1debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶, 不能高于999900 单位:分 + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + List levelList = item.getCreditCardPaywayFee().getLevelList(); + // 银联二档贷记卡扫码费率(<=1000) + bank2creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2creditFeeJson.put("rateFee", convertRate(levelList.get(0).getFeeRate())); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + bank2creditFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + + // 银联一档贷记卡扫码费率(>1000) + bank1creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1creditFeeJson.put("rateFee", convertRate(levelList.get(1).getFeeRate())); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1creditFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + + } + } + + // 线上费率使用同一个费率 + if (CS.PAY_WAY_CODE.SCAN.equals(item.getWayCode())) { + wxPayFeeJson.put("rateType", "0"); // 默认为百分比费率 + wxPayFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 费率值 + wxPayFeeJson.put("rateBottom", "1"); // 默认封底金额 + + aliPayFeeJson.put("rateType", "0"); // 默认为百分比费率 + aliPayFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 费率值 + aliPayFeeJson.put("rateBottom", "1"); // 默认封底金额 + + // 银联二档借记卡扫码费率(<=1000) + bank2debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2debitFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + bank2debitFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank2debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶 单位:分 + + // 银联一档借记卡扫码费率(>1000) + bank1debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1debitFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1debitFeeJson.put("rateBottom", Math.max(item.getMinFee(), 1) + ""); // 借记卡手续费封底 单位:分 + bank1debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶, 不能高于999900 单位:分 + + // 银联二档贷记卡扫码费率(<=1000) + bank2creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2creditFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 贷记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + bank2creditFeeJson.put("rateBottom", "1"); // 贷记卡手续费封底 单位:分 + + // 银联一档贷记卡扫码费率(>1000) + bank1creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1creditFeeJson.put("rateFee", convertRate(item.getFeeRate())); // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1creditFeeJson.put("rateBottom", "1"); // 贷记卡手续费封底 单位:分 + } + } + + if (!wxPayFeeJson.containsKey("rateType")) throw new BizException("请配置微信单笔费率"); + if (!aliPayFeeJson.containsKey("rateType")) throw new BizException("请配置支付宝单笔费率"); + if (!bank1debitFeeJson.containsKey("rateType")) { + // 配置默认费率 + bank1debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1debitFeeJson.put("rateFee", "0.6"); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1debitFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank1debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶, 不能高于999900 单位:分 + +// throw new BizException("请配置借记卡 (金额>1000) 银联阶梯费率"); + }; + if (!bank2debitFeeJson.containsKey("rateType")) { + // 配置默认费率 + bank2debitFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2debitFeeJson.put("rateFee", "0.6"); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank2debitFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank2debitFeeJson.put("rateTop", "999900"); // 借记卡手续费封顶, 不能高于999900 单位:分 +// throw new BizException("请配置借记卡 (金额<=1000) 银联阶梯费率"); + } + + if (!bank1creditFeeJson.containsKey("rateType")) { + // 银联一档贷记卡扫码费率(>1000) + bank1creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank1creditFeeJson.put("rateFee", "0.6"); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + bank1creditFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + +// throw new BizException("请配置贷记卡 (金额>1000) 银联阶梯费率"); + } + + if (!bank2creditFeeJson.containsKey("rateType")) { + // 银联二档贷记卡扫码费率(<=1000) + bank2creditFeeJson.put("rateType","0");// 收费方式 只支持0按百分比 + bank2creditFeeJson.put("rateFee", "0.60"); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + bank2creditFeeJson.put("rateBottom", "1"); // 借记卡手续费封底 单位:分 + bank2creditFeeJson.put("rateTop", "1700"); // 借记卡手续费封顶 单位:分 + +// throw new BizException("请配置贷记卡 (金额<=1000) 银联阶梯费率"); + } + + codeScanT1FeeJSON.put("wxPayFee", wxPayFeeJson); + codeScanT1FeeJSON.put("aliPayFee", aliPayFeeJson); + codeScanT1FeeJSON.put("bank1debitPayFee", bank1debitFeeJson); + codeScanT1FeeJSON.put("bank2debitPayFee", bank2debitFeeJson); + codeScanT1FeeJSON.put("bank1creditPayFee", bank1creditFeeJson); + codeScanT1FeeJSON.put("bank2creditPayFee", bank2creditFeeJson); + + return codeScanT1FeeJSON; + } + + /** + * @author: xiaoyu + * @date: 2022/7/21 9:38 + * @describe: 交易权限及费率配置参数 + */ + public static JSONObject convertPayConfig(List paywayFeeList) { + JSONObject result = new JSONObject(); + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + // 交易权限 + ArrayList list = new ArrayList<>(); + // 费率 + JSONObject feeJson = new JSONObject(); + + paywayFeeList.forEach(item -> { + String bizProductCode = ""; + switch (item.getWayCode()){ + case CS.PAY_WAY_CODE.WX_LITE: bizProductCode = "1"; break; + case CS.PAY_WAY_CODE.WX_JSAPI: bizProductCode = "2"; break; + case CS.PAY_WAY_CODE.WX_BAR: bizProductCode = "3"; break; + case CS.PAY_WAY_CODE.ALI_QR: bizProductCode = "4"; break; + case CS.PAY_WAY_CODE.ALI_BAR: bizProductCode = "5"; break; + case CS.PAY_WAY_CODE.ALI_JSAPI: bizProductCode = "6"; break; + case CS.PAY_WAY_CODE.ALI_LITE: bizProductCode = "6"; break; + case CS.PAY_WAY_CODE.UP_BAR: bizProductCode = "8"; break; + case CS.PAY_WAY_CODE.YSF_JSAPI: bizProductCode = "9"; break; + case CS.PAY_WAY_CODE.UP_QR: bizProductCode = "7"; break; + } + if (StringUtils.isNotEmpty(bizProductCode)) { + list.add(bizProductCode); + } + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + // [微信]默认为百分比费率 + feeJson.put("rscanWxFeeType", "1"); + // [微信]默认封底金额 + feeJson.put("rscanWxFeeNum", "0"); + + feeJson.put("rscanWxFeeRate", convertRate(item.getFeeRate()) + ""); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + // [支付宝]默认为百分比费率 + feeJson.put("rscanAliFeeType", "1"); + // [支付宝]默认封底金额 + feeJson.put("rscanAliFeeNum", "0"); + + feeJson.put("rscanAliFeeRate", convertRate(item.getFeeRate()) + ""); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("UP_") || item.getWayCode().startsWith("YSF_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 银联借记卡一档费率类型 1-百分比 + feeJson.put("rscanDebitType1", "1"); + // 银联借记卡二档费率类型 1-百分比 + feeJson.put("rscanDebitType2", "1"); + + // 银联贷记卡一档费率类型 1-百分比 + feeJson.put("rscanCreditType1", "1"); + // 银联贷记卡二档费率类型 1-百分比 + feeJson.put("rscanCreditType2", "1"); + + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + + feeJson.put("rscanDebitNum2", convertRate(item.getLevelList().get(0).getFeeRate()) + ""); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + feeJson.put("rscanDebitMin2", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + feeJson.put("rscanDebitMax2", item.getMaxFee() + ""); // 借记卡手续费封顶 单位:分 + + feeJson.put("rscanDebitNum1", convertRate(item.getLevelList().get(1).getFeeRate()) + ""); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("rscanDebitMin1", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + feeJson.put("rscanDebitMax1", item.getMaxFee() + ""); // 借记卡手续费封顶 单位:分 + + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + + feeJson.put("rscanCreditNum2", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate()) + ""); // 贷记卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + feeJson.put("rscanCreditMin2", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + + feeJson.put("rscanCreditNum1", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate()) + ""); // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("rscanCreditMin1", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + + } + } + + }); + + if (CollUtil.isNotEmpty(list)) { + // 开通类型排序去重复 + ArrayList listCollect = new ArrayList<>(new TreeSet<>(list)); + String collect = String.join(",", listCollect); + result.put("scanServiceOpen", collect); + } + result.put("easyFeeBean", feeJson); + } + return result; + } + + + /** + * @author: xiaoyu + * @date: 2022/7/21 9:38 + * @describe: 交易权限及费率配置参数 + */ + public static JSONObject convertApplymentPayConfig(List paywayFeeList) { + JSONObject feeJson = new JSONObject(); + // 费率设置列表 + if (CollectionUtils.isNotEmpty(paywayFeeList)) { + // 费率 + paywayFeeList.forEach(item -> { + if (PaywayFee.FEE_TYPE_SINGLE.equals(item.getFeeType())) { + // 微信费率 + if (item.getWayCode().startsWith("WX_")) { + feeJson.put("wechatSignRate", convertRate(item.getFeeRate())); + // [微信]默认封底金额 + feeJson.put("wechatSignMin", "1"); + } + // 支付宝费率 + if (item.getWayCode().startsWith("ALI_")) { + feeJson.put("alipaySignRate", convertRate(item.getFeeRate())); + // [支付宝]默认封底金额 + feeJson.put("alipaySignMin", "1"); + } + } + + // 阶梯费率 + if ((item.getWayCode().startsWith("UP_") || item.getWayCode().startsWith("YSF_")) && PaywayFee.FEE_TYPE_LEVEL.equals(item.getFeeType())) { + // 借记卡费率 + if(CollUtil.isNotEmpty(item.getLevelList())){ + + feeJson.put("debitRate2", convertRate(item.getLevelList().get(0).getFeeRate())); // 借记卡手续费费率(单笔交易≤1000元) 参数单位为‰ + feeJson.put("debitMin2", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + feeJson.put("debitMax2", item.getMaxFee() + ""); // 借记卡手续费封顶 单位:分 + + feeJson.put("debitRate1", convertRate(item.getLevelList().get(1).getFeeRate())); // 借记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("debitMin1", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + feeJson.put("debitMax1", item.getMaxFee() + ""); // 借记卡手续费封顶 单位:分 + + } + + // 贷记卡费率 + if(item.getCreditCardPaywayFee() != null && CollUtil.isNotEmpty(item.getCreditCardPaywayFee().getLevelList())){ + + feeJson.put("creditRate2", convertRate(item.getCreditCardPaywayFee().getLevelList().get(0).getFeeRate())); // 贷记卡手续费费率 (单笔交易≤1000元) 参数单位为‰ + feeJson.put("creditMin2", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + + feeJson.put("creditRate1", convertRate(item.getCreditCardPaywayFee().getLevelList().get(1).getFeeRate())); // 贷记卡手续费费率(单笔交易>1000元) 参数单位为‰ + feeJson.put("creditMin1", item.getMinFee() + ""); // 借记卡手续费封底 单位:分 + + } + } + + }); + } + return feeJson; + } + + private static String convertRate(BigDecimal rate){ + return rate == null ? null : String.valueOf(rate.multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP)); + } + + @Override + public String bankBranchNo() { + return bankSubCode; + } + + @Override + public String bankAccountName() { + return StringUtils.defaultString(getDiySettAccountName(), getIdcardName()); + } + + public String getSettAccountName() { + if ("Y".equals(isUncrpSett)) { + return settAccountName; + } else { + return idcardName; + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ZftpayApplymentInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ZftpayApplymentInfo.java new file mode 100644 index 0000000..9bac668 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/applyment/ZftpayApplymentInfo.java @@ -0,0 +1,149 @@ +package com.jeequan.jeepay.core.model.applyment; + +import com.alibaba.fastjson.JSONArray; +import com.jeequan.jeepay.core.entity.MchApplyment; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class ZftpayApplymentInfo extends ApplymentBasicInfo{ + + /** 类型转换:标准格式 ---》 接口自定义格式 **/ + public String convertMerchantType(){ +// 商户类型 01-企业 02-事业单位 03-民办非企业组织 04-社会团体 05-党政及国家机关 06-个人商户 07-个体工商户 + if(this.merchantType == null){ + return null; + } + + if(this.merchantType == MchApplyment.MERCHANT_TYPE_PERSONAL){ + return "06"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_INDIVIDUAL){ + return "07"; + }else if(this.merchantType == MchApplyment.MERCHANT_TYPE_ENTERPRISE){ + return "01"; + } + return null; + } + + public static final byte APPLY_TYPE_OLD = 1; // 旧接口 + public static final byte APPLY_TYPE_NEW = 2; // 新接口 + + /** 进件类型 1-普通进件(旧接口) 2-免证件进件(新接口)**/ + public Byte applyType; + + /** 【结算银行卡信息】-开户行所在省 **/ + public String accountInstProvince; + + /** 【结算银行卡信息】-开户行所在市 **/ + public String accountInstCity; + + /** 【结算银行卡信息】-开户行支行名称 **/ + public String accountBranchName; + + /** 【结算银行卡信息】-卡类型:DC-借记卡 CC-信用卡 **/ + public String usageType; + + /** 【结算银行卡信息】-开户行简称缩写 **/ + public String accountInstId; + + /** 结算支付宝账号 **/ + public String alipayLogonId; + + /** 默认结算类型:bankCard-结算到银行卡 alipayAccount-结算到支付宝账号 **/ + public String defaultSettleType; + + /** 【商户行业资质】-资质类型 **/ + public String industryQualificationType; + + /** 【商户行业资质】-资质图片 **/ + public String industryQualificationImage; + + /** 服务类型:当面付、app支付、wap支付、电脑支付、线上资金预授权、新当面资金预授权、商户代扣、小程序支付 **/ + public JSONArray zftService; + + /** 【站点信息】 **/ + public JSONArray siteInfos; + + /** 商户支付宝账号 **/ + public String bindingAlipayLogonId; + + /** 授权函照片 **/ + public String getLicenseAuthLetterImage() { + return letterOfAuthPic; + } + + /** 补充资料 【证件类型】 **/ + public String additionalCertType; + + /** 补充资料 【证件号】 **/ + public String additionalCertNo; + + /** 补充资料 【证件图片】 **/ + public String additionalCertImage; + + public static final Map MERCHANT_TYPE_MAP = new HashMap<>(); + static { + MERCHANT_TYPE_MAP.put("01", "201"); // 企业 + MERCHANT_TYPE_MAP.put("02", "218"); // 事业单位 + MERCHANT_TYPE_MAP.put("03", "204"); // 民办非企业组织 + MERCHANT_TYPE_MAP.put("04", "206"); // 社会团体 + MERCHANT_TYPE_MAP.put("05", "219"); // 党政及国家机关 + MERCHANT_TYPE_MAP.put("06", "100"); // 个人商户 + MERCHANT_TYPE_MAP.put("07", "201"); // 个体工商户 + } + + /** + * @author: xiaoyu + * @date: 2022/4/12 9:29 + * @describe: 商户签约服务 + */ + public List getServiceList() { + List list = new ArrayList<>(); + if (this.zftService != null) { + for (int i = 0; i < this.zftService.size(); i++) { + list.add(this.zftService.get(i).toString()); + } + } + return list; + } + + /** + * @author: xiaoyu + * @date: 2022/4/12 11:44 + * @describe: 行业编码 + */ + public String getMccCodeNum() { + if (StringUtils.isNotEmpty(this.mccCode)) { + String[] code = this.mccCode.split("_"); + + if (code.length > 1) { + return code[1]; + } + } + return null; + } + + /** + * @author: xiaoyu + * @date: 2022/4/12 14:38 + * @describe: 账号使用类型转换 + */ + public String getUseType() { + if (MchApplyment.SETT_ACCOUNT_TYPE_CORPORATE.equals(this.getSettAccountType())) { + return "01"; + }else if (MchApplyment.SETT_ACCOUNT_TYPE_PERSONAL.equals(this.getSettAccountType())) { + return "02"; + } + return null; + } + + @Override + public String bankBranchNo() { + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptParams.java new file mode 100644 index 0000000..92aeef1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptParams.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.core.model.autopos; + +import com.jeequan.jeepay.core.entity.MchStoreDevice; +import lombok.Data; + +/** + * 智能POS 通知 + * + * @since 2021-09-28 + */ +@Data +public class ChannelOrderAcceptParams { + + public static String TRADE_TYPE_PAYMENT = "PAYMENT"; // 收款通知 + public static String TRADE_TYPE_REFUND = "REFUND"; // 退款通知 + + // 通知唯一索引类型 + public static byte NOTIFY_TYPE_DEVICE_NO = 1; // 设备号 + + /** 交易类型,PAYMENT-收款 REFUND-退款 */ + private String tradeType; + + /** 设备类型 */ + private Byte deviceType; + + /** 设备号 */ + private String deviceNo; + + /** 通知数据 */ + private Object acceptData; + + public ChannelOrderAcceptParams(Byte deviceType, String tradeType, String deviceNo, Object acceptData) { + this.deviceType = deviceType; + this.tradeType = tradeType; + this.deviceNo = deviceNo; + this.acceptData = acceptData; + } + + /** + * 构建智能POS通知数据 + */ + public static ChannelOrderAcceptParams buildAutoPosParams(String tradeType, String deviceNo, Object acceptData) { + return new ChannelOrderAcceptParams(MchStoreDevice.DEVICE_TYPE_AUTO_POS, tradeType, deviceNo, acceptData); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptRetMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptRetMsg.java new file mode 100644 index 0000000..3d9d451 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/autopos/ChannelOrderAcceptRetMsg.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.model.autopos; + +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.*; +import lombok.experimental.Accessors; + +/** + * 渠道处理返回数据类 + * + * @since 2021-09-28 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +public class ChannelOrderAcceptRetMsg extends ChannelRetMsg { + + /** 上游渠道返回订单/退款金额,单位分 **/ + private Long channelAmount; + + /** 上游渠道返回订单手续费,单位分 **/ + private Long channelFee; + + /** 上游渠道返回支付方式 **/ + private String channelWayCode; + + /** 上游渠道返回支付方式类型 **/ + private String channelWayCodeType; + + /** 系统订单号/退款单号(一般用于pos机订单接收模式,根据此订单号查询重复订单) **/ + private String bizOrderId; + + /** 原渠道订单号(对应支付订单的渠道订单号),退款时使用 **/ + private String channelPayOrderId; + + /** 原渠道订单是否需要分账 0-不分账 1-自动分账 2-手动分账。此字段为空,则使用系统默认分账配置 **/ + private Byte channelDivisionMode; + + /** 原渠道订单是否自动退分账 0-需主动分账 1-渠道自动退分账,系统不主动调用。 此字段为空,则系统主动调用退分账 **/ + private Byte channelDivisionRefundMode; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBill.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBill.java new file mode 100644 index 0000000..da2bb85 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBill.java @@ -0,0 +1,82 @@ +package com.jeequan.jeepay.core.model.bill; + +import lombok.Data; + +import java.util.Date; + +/*** + * 渠道对账单数据类 + * + * @author zx + * + * @date 2021/12/30 9:01 + */ +@Data +public class ChannelBill { + + /** + * 批次号 + */ + private String batchNo; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 渠道商户号 + */ + private String channelMchNo; + + /** + * 对账日期 + */ + private Date billDate; + + /** + * 账单类型,pay:支付, refund:退款 + */ + private String billType; + + /** + * 渠道商户订单号 + */ + private String orderId; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 渠道订单状态:0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte channelState; + + /** + * 渠道交易金额,单位分 + */ + private Long channelAmount; + + /** + * 渠道手续费,单位分 + */ + private Long channelFeeAmount; + + /** + * 渠道交易成功时间 + */ + private Date channelSuccessAt; + + /** + * 渠道用户标识 + */ + private String channelUser; + + /** + * 渠道退款原支付订单号 + */ + private String orgPayOrderId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRQ.java new file mode 100644 index 0000000..f574fd8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRQ.java @@ -0,0 +1,106 @@ +package com.jeequan.jeepay.core.model.bill; + +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import lombok.Data; + +import java.util.List; +import java.util.Set; + +/*** + * 渠道对账单请求参数类 + * + * @author zx + * + * @date 2021/12/30 9:01 + */ +@Data +public class ChannelBillRQ { + + public static final String INFO_TYPE_ISV = "isv"; + public static final String INFO_TYPE_SUB = "sub"; + public static final String INFO_TYPE_NORMAL = "normal"; + + /** + * 渠道商户号 + */ + private String channelMchNo; + + /** + * 商户应用 + */ + private String infoId; + + /** + * 渠道账单维度:isv - 服务商,sub - 特约商户,normal - 普通商户 + */ + private String infoType; + + /** + * 服务商参数 + */ + private IsvParams isvParams; + + /** + * 特约商户参数 + */ + private IsvsubMchParams isvsubMchParams; + + /** + * 普通商户参数 + */ + private NormalMchParams normalMchParams; + + /** + * channelMchNo 对应的 商户应用appId列表/服务商号列表 + */ + private List infoIdList; + + /** + * 【用于服务商对账维度】 <本地订单要忽略的应用AppId集合,渠道账单要忽略的子商户号集合> + */ + private Set ignoreCheckBillMchNos; + + + public ChannelBillRQ() { + } + + public ChannelBillRQ(String channelMchNo, String infoId, String infoType, IsvParams isvParams, IsvsubMchParams isvsubMchParams, NormalMchParams normalMchParams, List infoIdList) { + this.channelMchNo = channelMchNo; + this.infoId = infoId; + this.infoType = infoType; + this.isvParams = isvParams; + this.isvsubMchParams = isvsubMchParams; + this.normalMchParams = normalMchParams; + this.infoIdList = infoIdList; + } + + public ChannelBillRQ(String channelMchNo, String infoId, String infoType, IsvParams isvParams, IsvsubMchParams isvsubMchParams, + NormalMchParams normalMchParams, List infoIdList, Set ignoreCheckBillMchNos) { + this.channelMchNo = channelMchNo; + this.infoId = infoId; + this.infoType = infoType; + this.isvParams = isvParams; + this.isvsubMchParams = isvsubMchParams; + this.normalMchParams = normalMchParams; + this.infoIdList = infoIdList; + this.ignoreCheckBillMchNos = ignoreCheckBillMchNos; + } + + /** 构建服务商维度对账配置参数 */ + public static ChannelBillRQ buildIsvChannelBillRQ(String channelMchNo, String infoId, IsvParams isvParams, List infoIdList, Set ignoreCheckBillMchNos) { + return new ChannelBillRQ(channelMchNo, infoId, INFO_TYPE_ISV, isvParams, null, null, infoIdList, ignoreCheckBillMchNos); + } + + /** 构建服务商子商户维度对账配置参数 */ + public static ChannelBillRQ buildSubMchChannelBillRQ(String channelMchNo, String infoId, IsvsubMchParams isvsubMchParams, List infoIdList) { + return new ChannelBillRQ(channelMchNo, infoId, INFO_TYPE_SUB, null, isvsubMchParams, null, infoIdList); + } + + /** 构建普通商户维度对账配置参数 */ + public static ChannelBillRQ buildNormalMchChannelBillRQ(String channelMchNo, String infoId, NormalMchParams normalMchParams, List infoIdList) { + return new ChannelBillRQ(channelMchNo, infoId, INFO_TYPE_NORMAL, null, null, normalMchParams, infoIdList); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRS.java new file mode 100644 index 0000000..c6d4c23 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/ChannelBillRS.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.bill; + +import com.jeequan.jeepay.core.entity.CheckBatch; +import lombok.Data; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; +import java.util.List; + +/* +* 上游渠道对账单 响应信息包装类 +* +* @author zx +* +* @date 2021/6/8 17:31 +*/ +@Slf4j +@Data +@Accessors(chain = true) +public class ChannelBillRS implements Serializable { + + /** 对账批次 **/ + private CheckBatch checkBatch; + + /** 渠道对账单列表 **/ + private List channelBillList; + +} + + + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/LocalBill.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/LocalBill.java new file mode 100644 index 0000000..6ca781c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/bill/LocalBill.java @@ -0,0 +1,97 @@ +package com.jeequan.jeepay.core.model.bill; + +import lombok.Data; + +import java.util.Date; + +/*** + * 本地对账单数据类 + * + * @author zx + * + * @date 2021/12/30 9:01 + */ +@Data +public class LocalBill { + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 渠道商户号 + */ + private String channelMchNo; + + /** + * 对账日期 + */ + private Date billDate; + + /** + * 账单类型,pay:支付, refund:退款 + */ + private String billType; + + /** + * 订单号 + */ + private String orderId; + + /** + * 三位货币代码,人民币:cny + */ + private String currency; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 商户名称 + */ + private String mchName; + + /** + * 商户应用appId + */ + private String mchAppId; + + /** + * 商户订单号 + */ + private String mchOrderNo; + + /** + * 交易金额,单位分 + */ + private Long amount; + + /** + * 手续费,单位分 + */ + private Long feeAmount; + + /** + * 支付订单状态:0-订单 生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte orderState; + + /** + * 退款订单状态:退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭 + */ + private Byte refundState; + + /** + * 交易成功时间 + */ + private Date orderSuccessAt; + + /** + * 下单时间 + */ + private Date orderCreateAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutParams.java new file mode 100644 index 0000000..31da739 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutParams.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.cashout; + +import lombok.Data; + +/* + * 提现配置信息 + * + * @author zx + * + * @date 2021/6/8 18:02 + */ +@Data +public class CashoutParams { + + /** 服务商是否开启提现 */ + private Byte isOpenIsvCashout; + + /** 商户是否开启 订单支付成功 自动提现 **/ + private Byte isOpenMchOrderCashout; + + /** 商户是否开启 定时任务 自动提现 **/ + private Byte isOpenMchTaskCashout; + + /** 最小提现金额 **/ + private String minCashoutAmount; + + /** 最大提现金额 **/ + private String maxCashoutAmount; + + /** 提现开始时间 **/ + private String startTime; + + /** 提现结束时间 **/ + private String endTime; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutRetMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutRetMsg.java new file mode 100644 index 0000000..550e710 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/cashout/CashoutRetMsg.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.cashout; + +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 提现 渠道返回数据类 + * + * @since 2022-11-14 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class CashoutRetMsg extends ChannelRetMsg { + + /** 提现银行名称 **/ + private String bankName; + + /** 提现账户 **/ + private String bankAccount; + + /** 提现账户名称 **/ + private String bankAccountName; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/IsvConfigContext.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/IsvConfigContext.java new file mode 100644 index 0000000..540a6ae --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/IsvConfigContext.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.core.model.context; + +import com.jeequan.jeepay.core.entity.IsvInfo; +import com.jeequan.jeepay.core.model.oauth2.Oauth2Params; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/* + * Isv支付参数信息 放置到内存, 避免多次查询操作 + * + * @author terrfly + * + * @date 2021/6/8 17:28 + */ +@Data +public class IsvConfigContext { + + /** isv信息缓存 */ + private String isvNo; + private IsvInfo isvInfo; + + /** 服务商 支付配置信息缓存 */ + private Map isvParamsMap = new HashMap<>(); + + /** 服务商 oauth2参数信息缓存 ( ISV默认的 oauth2参数, k-v : wxpay - 对象 ) + * + * 20230110: 添加特殊定义, 当包含其他oauth2渠道时, key: DIYLIST_V12312_LIST_20220101_wxpay + * */ + private Map oauth2ParamsMap = new HashMap<>(); + + /** 服务商选择的oauth2条目, <接口代码, 选择条目> */ + private Map oauth2SelectedInfoId = new HashMap<>(); + + /** 获取isv配置信息 **/ + public IsvParams getIsvParams(Object ifCodeOrAltId){ + return isvParamsMap.get(ifCodeOrAltId); + } + + /** 获取isv配置信息 **/ + public T getIsvParams(String ifCode, Class cls){ + return (T)isvParamsMap.get(ifCode); + } + + /** 获取isv oatuh2配置信息 **/ + public Oauth2Params getOauth2ParamsByIfCode(String ifCode){ + return oauth2ParamsMap.get(ifCode); + } + + /** 获取isv oatuh2配置信息 **/ + public T getOauth2ParamsByIfCode(String ifCode, Class cls){ + return (T)oauth2ParamsMap.get(ifCode); + } + + /** 放置 其他oauth2参数 **/ + public void putOauth2ParamsMapByDiyList(String infoId, String ifCode, Oauth2Params oauth2Params){ + oauth2ParamsMap.put("DIYLIST_"+infoId+ "_" + ifCode, oauth2Params); + } + + /** get 其他oauth2参数 **/ + public Oauth2Params queryOauth2ParamsMapByDiyList(String infoId, String ifCode){ + return oauth2ParamsMap.get("DIYLIST_"+infoId+ "_" + ifCode); + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchAppConfigContext.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchAppConfigContext.java new file mode 100644 index 0000000..3d7f12d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchAppConfigContext.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.core.model.context; + +import com.jeequan.jeepay.core.entity.MchApp; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchInfo; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.core.model.oauth2.Oauth2Params; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.HashMap; +import java.util.Map; + +/* +* 商户应用支付参数信息 +* 放置到内存, 避免多次查询操作 +* +* @author terrfly +* +* @date 2021/6/8 17:29 +*/ +@Data +@Accessors(chain = true) +public class MchAppConfigContext { + + + /** 商户信息缓存 */ + private String mchNo; + private String appId; + private Byte mchType; + private MchInfo mchInfo; + private MchApp mchApp; + private MchApplyment mchApplyment; + private PaywayFee tradeRate; + private PaywayFee d0Rate; + private MchStore mchStore; + + /** 商户支付配置信息缓存, <接口代码, 支付参数> */ + private Map normalMchParamsMap = new HashMap<>(); + private Map isvsubMchParamsMap = new HashMap<>(); + + /** oauth2参数信息缓存 (应该只有普通商户拥有该参数) */ + private Map oauth2ParamsMap = new HashMap<>(); + + /** 放置所属服务商的信息 **/ + protected IsvConfigContext isvConfigContext; + + /** 获取普通商户配置信息 **/ + public NormalMchParams getNormalMchParamsByIfCode(String ifCode){ + return normalMchParamsMap.get(ifCode); + } + + + /** 获取isv配置信息 **/ + public T getNormalMchParamsByIfCode(String ifCode, Class cls) { + NormalMchParams mchParams = normalMchParamsMap.get(ifCode); + if (cls.isInstance(mchParams)) { + return cls.cast(mchParams); + } + return null; + } + + /** 获取特约商户配置信息 **/ + public IsvsubMchParams getIsvsubMchParamsByIfCode(String ifCode){ + return isvsubMchParamsMap.get(ifCode); + } + + /** 获取isv配置信息 **/ + public T getIsvsubMchParamsByIfCode(String ifCode, Class cls) { + IsvsubMchParams mchParams = isvsubMchParamsMap.get(ifCode); + if (cls.isInstance(mchParams)) { + return cls.cast(mchParams); + } + return null; + } + + /** 获取isv oatuh2配置信息 **/ + public Oauth2Params getOauth2ParamsByIfCode(String ifCode){ + return oauth2ParamsMap.get(ifCode); + } + + /** 获取isv oatuh2配置信息 **/ + public T getOauth2ParamsByIfCode(String ifCode, Class cls) { + Oauth2Params mchParams = oauth2ParamsMap.get(ifCode); + if (cls.isInstance(mchParams)) { + return cls.cast(mchParams); + } + return null; + } + + /** 是否为 服务商特约商户 **/ + public boolean isIsvsubMch(){ + return this.mchType == MchInfo.TYPE_ISVSUB; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchInfoConfigContext.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchInfoConfigContext.java new file mode 100644 index 0000000..06a53d9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/context/MchInfoConfigContext.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.context; + +import com.jeequan.jeepay.core.entity.MchApp; +import com.jeequan.jeepay.core.entity.MchInfo; +import lombok.Data; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/* +* 商户配置信息 +* 放置到内存, 避免多次查询操作 +* +* @author terrfly +* +* @date 2021/6/8 17:29 +*/ +@Data +public class MchInfoConfigContext { + + + /** 商户信息缓存 */ + private String mchNo; + private Byte mchType; + private MchInfo mchInfo; + private Map appMap = new ConcurrentHashMap<>(); + + /** 重置商户APP **/ + public void putMchApp(MchApp mchApp){ + appMap.put(mchApp.getAppId(), mchApp); + } + + /** get商户APP **/ + public MchApp getMchApp(String appId){ + return appMap.get(appId); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/BsjParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/BsjParams.java new file mode 100644 index 0000000..8e6d4d3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/BsjParams.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 博实结 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class BsjParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public BsjParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public BsjParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * appId + */ + private String appId; + + /** + * appSecret + */ + private String appSecret; + + /** + * userCode + */ + private String userCode; + + /** + * 支付成功语音播报内容 + */ + private String customContent; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getAppSecret())) { + params.setAppSecret(StringKit.autoDesensitization(params.getAppSecret())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/DeviceParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/DeviceParams.java new file mode 100644 index 0000000..7833ba8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/DeviceParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; + +/** + * 抽象类 设备参数定义 + * + * @author zx + * + * @date 2021/6/8 16:33 + */ +public abstract class DeviceParams { + + public final static byte MODE_PRINT = 1; // 仅打印 + public final static byte MODE_SPEAK = 2; // 仅播报 + public final static byte MODE_PRINT_AND_SPEAK = 3; // 打印并播报 + + public static DeviceParams factory(String provider, String providerParamStr){ + + if(CS.DEVICE_PROVIDER.BSJ.equals(provider)){ + BsjParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, BsjParams.ProviderParams.class); + return new BsjParams(providerParams); + }else if(CS.DEVICE_PROVIDER.PS.equals(provider)){ + PsSpeakerParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, PsSpeakerParams.ProviderParams.class); + return new PsSpeakerParams(providerParams); + }else if(CS.DEVICE_PROVIDER.ZGWL.equals(provider)){ + ZgwlParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, ZgwlParams.ProviderParams.class); + return new ZgwlParams(providerParams); + }else if(CS.DEVICE_PROVIDER.FE.equals(provider)){ + FePrinterParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, FePrinterParams.ProviderParams.class); + return new FePrinterParams(providerParams); + }else if(CS.DEVICE_PROVIDER.ZW.equals(provider)){ + ZwParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, ZwParams.ProviderParams.class); + return new ZwParams(providerParams); + }else if(CS.DEVICE_PROVIDER.JSD.equals(provider)){ + JsdParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, JsdParams.ProviderParams.class); + return new JsdParams(providerParams); + }else if(CS.DEVICE_PROVIDER.LLZN.equals(provider)){ + LlznParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, LlznParams.ProviderParams.class); + return new LlznParams(providerParams); + } else if (CS.DEVICE_PROVIDER.YLY.equals(provider)) { + YlyParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, YlyParams.ProviderParams.class); + return new YlyParams(providerParams); + }else if (CS.DEVICE_PROVIDER.LKLS.equals(provider)) { + LklsParams.ProviderParams providerParams = JSONObject.parseObject(providerParamStr, LklsParams.ProviderParams.class); + return new LklsParams(providerParams); + } + return null; + } + + /** + * 敏感数据脱敏 + */ + public abstract String deSenData(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/FePrinterParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/FePrinterParams.java new file mode 100644 index 0000000..964c843 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/FePrinterParams.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 飞鹅云打印 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class FePrinterParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public FePrinterParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public FePrinterParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * 飞鹅云后台帐号名USER + */ + private String user; + + /** + * 飞鹅云后台帐号UKEY + */ + private String ukey; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + /** + * 设备key + */ + private String deviceKey; + + /** + * 设备名称 + */ + private String deviceName; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getUkey())) { + params.setUkey(StringKit.autoDesensitization(params.getUkey())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/JsdParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/JsdParams.java new file mode 100644 index 0000000..9739a2d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/JsdParams.java @@ -0,0 +1,90 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 金士盾 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class JsdParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public JsdParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public JsdParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * accessKey + */ + private String accessKey; + + /** + * accessKeySecret + */ + private String accessKeySecret; + + /** + * 支付成功语音播报内容 + */ + private String customContent; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getAccessKey())) { + params.setAccessKey(StringKit.autoDesensitization(params.getAccessKey())); + } + if (params != null && StringUtils.isNotBlank(params.getAccessKeySecret())) { + params.setAccessKeySecret(StringKit.autoDesensitization(params.getAccessKeySecret())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LklsParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LklsParams.java new file mode 100644 index 0000000..f6c067e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LklsParams.java @@ -0,0 +1,113 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2023/12/25 11:26 + */ +@Data +public class LklsParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public ExtParams extParams; + + public LklsParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public LklsParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams,ExtParams extParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + this.extParams = extParams; + } + + @Data + public static class ProviderParams { + /** + * 支付成功语音播报内容 + */ + private String customContent; + + /** + * appId + */ + private String appId; + + /** + * appSecret + */ + private String appSecret; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Data + public static class ExtParams { + + /** + * 绑定状态 + */ + private Integer bindState; + /** + * 用户号 + */ + private String mchNo; + + /** + * 通道号 + */ + private String isvNo; + + /** + * 门店编号 + */ + private Long storeId; + + + /** + * 通道商编 + */ + private String merchantId; + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + return JSONObject.toJSONString(params); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LlznParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LlznParams.java new file mode 100644 index 0000000..1c49745 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/LlznParams.java @@ -0,0 +1,82 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 零零智能 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class LlznParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public LlznParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public LlznParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * apiKey + */ + private String apiKey; + + /** + * 支付成功语音播报内容 + */ + private String customContent; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getApiKey())) { + params.setApiKey(StringKit.autoDesensitization(params.getApiKey())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PayOrderInfo4Device.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PayOrderInfo4Device.java new file mode 100644 index 0000000..a246063 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PayOrderInfo4Device.java @@ -0,0 +1,82 @@ +package com.jeequan.jeepay.core.model.device; + +import lombok.Data; + +import java.util.Date; + +/*** + * 播报订单内容信息 + * + * @author zx + * + * @date 2021/12/30 9:01 + */ +@Data +public class PayOrderInfo4Device { + + public final static String BOARD_TYPE_CANCEL = "CANCEL"; // 取消支付播报类型 + public final static String BOARD_TYPE_MEMBER = "MEMBER"; // 会员余额支付播报类型 + + public static int EXPIRED_TIME = 5; // 订单播报超时时间,单位:分钟 + + /** + * 支付订单号 + */ + private String payOrderId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 门店ID + */ + private String storeId; + + /** + * 码牌ID + */ + private Long qrcId; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 支付方式代码 + */ + private String wayCode; + + /** + * 支付方式名称 + */ + private String wayName; + + /** + * 支付方式名称 + */ + private String wayCodeType; + + /** + * 门店名称 + */ + private String storeName; + + /** + * 支付金额,单位分 + */ + private Long amount; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginCdKeyParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginCdKeyParams.java new file mode 100644 index 0000000..da9a0b1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginCdKeyParams.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.core.model.device; + +import lombok.Data; + +/*** +* 收银插件 激活码参数 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class PluginCdKeyParams { + + /** + * 激活码, 8-16数字 + */ + private String cdKey; + + /** + * 有效期止,0-长期 + */ + private String expiredTime; + + /** + * 激活时间 + */ + private String activeTime; + + /** + * 解除激活时间 + */ + private String deActiveTime; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginProviderParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginProviderParams.java new file mode 100644 index 0000000..3db305e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PluginProviderParams.java @@ -0,0 +1,42 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 收银插件 厂商参数 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class PluginProviderParams { + + /** + * 默认商品标题 + */ + private String subject; + + /** + * 默认商品描述 + */ + private String body; + + /** + * appSecret + */ + private String appSecret; + + + public String deSenData() { + if (StringUtils.isNotBlank(this.appSecret)) { + this.appSecret = StringKit.autoDesensitization(this.appSecret); + } + + return JSONObject.toJSONString(this); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PosParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PosParams.java new file mode 100644 index 0000000..0fe6564 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PosParams.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 扫码POS 参数 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class PosParams { + + /** + * appId + */ + private String appId; + + /** + * appSecret + */ + private String appSecret; + + + public String deSenData() { + + if (StringUtils.isNotBlank(this.appSecret)) { + this.appSecret = StringKit.autoDesensitization(this.appSecret); + } + + return JSONObject.toJSONString(this); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PsSpeakerParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PsSpeakerParams.java new file mode 100644 index 0000000..d430a81 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/PsSpeakerParams.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 品生 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class PsSpeakerParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public PsSpeakerParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public PsSpeakerParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * appId + */ + private String username; + + /** + * appSecret + */ + private String password; + + /** + * 支付成功语音播报内容 + */ + private String customContent; + + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getPassword())) { + params.setPassword(StringKit.autoDesensitization(params.getPassword())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/YlyParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/YlyParams.java new file mode 100644 index 0000000..09da8a5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/YlyParams.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 易联云 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class YlyParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public YlyParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public YlyParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * clientId + */ + private String clientId; + + /** + * clientSecret + */ + private String clientSecret; + + /** + * accessToken + */ + private String accessToken; + + /** + * keywords K8设备关键词 + */ + private String keywords; + + /** + * printSetIcon 打印LOGO配置 + */ + private String printSetIcon; + + /** + * pushMsgKey 推送应用公钥 + */ + private String pushPublicKey; + + /** + * pushMsgKey 易联云公钥 + */ + private String platPublicKey; + + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + /** + * 终端秘钥 + */ + private String deviceKey; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getClientSecret())) { + params.setClientSecret(StringKit.autoDesensitization(params.getClientSecret())); + } + if (params != null && StringUtils.isNotBlank(params.getAccessToken())) { + params.setAccessToken(StringKit.autoDesensitization(params.getAccessToken())); + } + if (params != null && StringUtils.isNotBlank(params.getPushPublicKey())) { + params.setPushPublicKey(StringKit.autoDesensitization(params.getPushPublicKey())); + } + if (params != null && StringUtils.isNotBlank(params.getPlatPublicKey())) { + params.setPlatPublicKey(StringKit.autoDesensitization(params.getPlatPublicKey())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZgwlParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZgwlParams.java new file mode 100644 index 0000000..a0dee7a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZgwlParams.java @@ -0,0 +1,102 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 智谷物联 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class ZgwlParams extends DeviceParams { + + public ZgwlParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public ZgwlParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + @Data + public static class ProviderParams { + /** + * accessKeyId + */ + private String accessKeyId; + + /** + * accessKeySecret + */ + private String accessKeySecret; + + /** + * 实例ID + */ + private String instanceId; + + /** + * 公网接入点 + */ + private String endPoint; + + /** + * Topic + */ + private String topic; + + /** + * GroupId + */ + private String groupId; + } + + @Data + public static class DeviceParams { + + /** + * 设备号 + */ + private String deviceNo; + + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getAccessKeySecret())) { + params.setAccessKeySecret(StringKit.autoDesensitization(params.getAccessKeySecret())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZwParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZwParams.java new file mode 100644 index 0000000..9f084ff --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/device/ZwParams.java @@ -0,0 +1,139 @@ +package com.jeequan.jeepay.core.model.device; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 厂商设备参数 智网 +* +* @author zx +* +* @date 2021/12/30 9:01 +*/ +@Data +public class ZwParams extends DeviceParams { + + public ProviderParams providerParams; + + public DeviceParams deviceParams; + + public BizConfigParams bizConfigParams; + + public ZwParams(ProviderParams providerParams) { + this.providerParams = providerParams; + } + + public ZwParams(ProviderParams providerParams, DeviceParams deviceParams, BizConfigParams bizConfigParams) { + this.providerParams = providerParams; + this.deviceParams = deviceParams; + this.bizConfigParams = bizConfigParams; + } + + @Data + public static class ProviderParams { + /** + * token + */ + private String token; + + /** + * md5Key + */ + private String md5Key; + + /** + * 支付成功语音播报内容 + */ + private String customContent; + } + + @Data + public static class DeviceParams { + + // 设备号 + private String deviceNo; + + // 是否配置打印机参数 0-不配置 1-配置 + private Byte configFlag; + + // 是否截获收银小票金额 0-关闭 1-开启 + private Integer billCap; + + // 收银小票打印标志 0-不打印 1-支付前打印 2-支付后打印(默认值) + private Integer billPrint; + + // 支付超时时间,单位:秒 超时退出支付并打印收银小票 + private Integer billTimeout; + + // 交易结果查询时间间隔,单位:秒 + private Integer queryInterval; + + // 最大交易结果查询次数 + private Integer queryNum; + + // 16字节唯一验证码 从开机时打印的参数配置码中提取 参数配置码格式:sn,authcode + private String authCode; + + // 支付错误信息打印标志 支付失败时是否打印错误信息 true-打印 false-不打印 默认值 + private Boolean errInfoPrint; + + // 退款码打印标志 支付成功小票中是否打印退款码 true-打印 默认值 false-不打印 + private Boolean refundCodePrint; + + // 厂商编号 如果为-1 人工配置参数 否则为预配置参数 + private String providerCode; + + /** 人工配置参数 **/ + // 获取收银小票支付金额关键字,每个关键字直接用逗号分隔,不能带空格 (实收,应收,总价,总计,合计) + private String keywordCap; + // 放弃支付(小票放行关键字),每个关键字直接用逗号分隔,不能带空格 (店名,销售商品报表) + private String keywordSkip; + // 收银单号前缀 + private String orderPrefix; + // 重复的订单编号,是否跳过 true/false + private Boolean orderSkip; + + /** 预配置参数 **/ + // 预配置时,收银小票金额拦截关键字,只允许一个关键字 + private String presetPrefix; + // 软件编号 + private String softCode; + // 软件名称 + private String softName; + // 时间戳 + private String timestamp; + // 支付参数 + private String presetData; + } + + @Data + public static class BizConfigParams { + + /** + * 打印联数 + */ + private Integer printNum; + + /** + * 打印机模式 + */ + private Byte printMode; + + } + + @Override + public String deSenData() { + ProviderParams params = this.getProviderParams(); + if (params != null && StringUtils.isNotBlank(params.getToken())) { + params.setToken(StringKit.autoDesensitization(params.getToken())); + } + if (params != null && StringUtils.isNotBlank(params.getMd5Key())) { + params.setMd5Key(StringKit.autoDesensitization(params.getMd5Key())); + } + + return JSONObject.toJSONString(params); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/Account.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/Account.java new file mode 100644 index 0000000..c0fd90a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/Account.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model.df; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * 账户信息 + * @author crystal + * @date 2024/3/25 10:49 + */ +@Data +@NoArgsConstructor +public class Account { + + private Long balance; + + private Long freeze; + + + public Account(Long balance, Long freeze) { + this.balance = balance; + this.freeze = freeze; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/PaymentSign.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/PaymentSign.java new file mode 100644 index 0000000..1bc5806 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/df/PaymentSign.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.df; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.AccountCashInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * 签约 + * @author crystal + * @date 2024/3/25 10:11 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PaymentSign { + + /** + * 用户名 + */ + private String userName; + + /** + * 身份证号 + */ + private String idCard; + + /** + * 手机号码 + */ + private String mobile; + + /** + * 结算银行名称 + */ + private String bankName; + + /** + * 结算账号 + */ + private String settleNo; + /** + * {"cashAmt": 10000, "bankName": "中国工商银行", "settleNo": "62122632004197881", + * "bankMobile": "13554638400", "settleCard": "420222199504044815", "settleName": "鲍志刚", + * "bankCardAreaCode": "[\"1001\",\"1000\",\"1021\"]", "bankCardAreaName": "北京市-北京市-东城区"} + * @param extra + */ + public PaymentSign(JSONObject extra) { + if(extra != null){ + AccountCashInfo accountCashInfo = extra.toJavaObject(AccountCashInfo.class); + this.userName = accountCashInfo.getSettleName(); + this.idCard = accountCashInfo.getSettleCard(); + this.mobile = accountCashInfo.getBankMobile(); + this.bankName = accountCashInfo.getBankName(); + this.settleNo = accountCashInfo.getSettleNo(); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/CashoutRecordExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/CashoutRecordExportExcel.java new file mode 100644 index 0000000..a2eb41a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/CashoutRecordExportExcel.java @@ -0,0 +1,96 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 提现记录表 + *

+ * + * @since 2023-08-30 + */ +@Data +public class CashoutRecordExportExcel { + + /** + * 提现记录ID + */ + @Excel(name = "申请单号") + private String rid; + + /** + * 名称快照 + */ + @Excel(name = "申请用户") + private String infoName; + + /** + * 申请金额 + */ + @Excel(name = "申请提现金额") + private BigDecimal applyAmount; + + /** + * 最终结算金额 (申请-手续费), 单位分 + */ + @Excel(name = "结算金额") + private BigDecimal settAmount; + + /** + * 手续费金额,单位分 + */ + @Excel(name = "手续费金额") + private BigDecimal settFeeAmount; + + /** + * 结算账户类型: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡 BANK_PUBLIC对公 BANK_PRIVATE对私 + */ + @Excel(name = "结算账户类型", replace = {"微信零钱_WXCASH", "支付宝转账_ALIPAYCASH", "银行卡_BANKCARD", "对公_BANKPUBLIC", "对私_BANKPRIVATE"}) + private String settAccountType; + + /** + * 结算账户名称 + **/ + @Excel(name = "结算账户名称") + private String settAccountName; + + /** + * 结算账户账号 + **/ + @Excel(name = "结算账户账号") + private String settAccountNo; + + /** + * 开户银行名称 + **/ + @Excel(name = "开户银行名称") + private String settAccountBank; + + /** + * 开户支行名称 + **/ + @Excel(name = "开户支行名称") + private String settAccountSubBank; + + /** + * 结算账户联系人手机号(一般为服务商手机号) + */ + @Excel(name = "结算账户联系人手机号") + private String settAccountTelphone; + + /** + * 结算审核状态: 1-审核中, 2-审核失败, 3-结算中, 4-结算成功, 5-结算失败 + */ + @Excel(name = "结算状态", replace = {"审核中_1", "审核失败_2", "结算中_3", "结算成功_4", "结算失败_5"}) + private String state; + + /** + * 创建时间 + */ + @Excel(name = "申请时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchPayOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchPayOrderExportExcel.java new file mode 100644 index 0000000..8ac6796 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchPayOrderExportExcel.java @@ -0,0 +1,203 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 支付订单表 + *

+ * + * @since 2021-09-28 + */ +@Data +public class MchPayOrderExportExcel { + + /** + * 支付订单号 + */ + @Excel(name = "平台单号") + private String payOrderId; + + /** + * 通道单号 + */ + @Excel(name = "通道单号") + private String channelOrderNo; + + /** + * 用户支付凭证交易单号 + */ + @Excel(name = "渠道单号") + private String platformOrderNo; + + /** + * 商户订单号 + */ + @Excel(name = "商户单号") + private String mchOrderNo; + + /** + * 用户支付凭证商户单号 + */ + @Excel(name = "落单号") + private String platformMchOrderNo; + + /** + * 商户名称 + */ + @Excel(name = "商户名称") + private String mchName; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchExtNo; + + /** + * 门店名称 + */ + @Excel(name = "门店名称") + private String storeName; + + /** + * 门店ID + */ + @Excel(name = "门店编号") + private String storeId; + + /** + * 应用名称 + */ + @Excel(name = "应用名称") + private String appName; + + + /** + * 应用编号 + */ + @Excel(name = "应用编号") + private String appId; + + + /** + * 支付通道 + */ + @Excel(name = "支付通道") + private String ifName; + + /** + * 所属渠道 + */ + @Excel(name = "所属渠道") + private String isvName; + + /** + * 支付金额 + */ + @Excel(name = "支付金额") + private BigDecimal amount; + + /** + * 退款金额 + */ + @Excel(name = "退款金额") + private BigDecimal refundAmount; + + /** + * 实际手续费 + */ + @Excel(name = "实际手续费") + private BigDecimal mchFeeAmount; + + /** + * 收单手续费 + */ + @Excel(name = "收单手续费") + private BigDecimal mchOrderFeeAmount; + + /** + * 商家费率 + */ + @Excel(name = "商家费率") + private String mchFeeRate; + + /** + * 垫资手续费 + */ + @Excel(name = "垫资手续费") + private String cashFee; + + /** + * 垫资手续费率 + */ + @Excel(name = "垫资手续费率") + private String cashRate; + /** + * 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 , 22-退款中 + */ + @Excel(name = "支付状态", replace = {"订单生成_0", "支付中_1", "支付成功_2", "支付失败_3", "已撤销_4", "已退款_5", "订单关闭_6" ,"退款中_22"}) + private String state; + + /** + * 结算类型 + */ + @Excel(name = "结算类型") + private String settleType; + + /** + * 借贷类型 + */ + @Excel(name = "借贷类型", replace = {"借记卡_00", "贷记卡_01", "微信零钱_02", "支付宝花呗_03", "支付宝其它_04", "数字货币_05", "其它_99"}) + private String drType; + + /** + * 分账状态 + */ + @Excel(name = "分账状态", replace = {"未发生分账_0", "等待分账任务处理_1", "分账处理中_2", "分账任务已结束_3"}) + private String divisionState; + + + + /** + * 退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款 + */ + @Excel(name = "退款状态", replace = {"未退款_0", "部分退款_1", "全额退款_2"}) + private String refundState; + + /** + * 支付方式代码 + */ + @Excel(name = "支付方式") + private String wayName; + + + /** + * 买家备注 + */ + @Excel(name = "买家备注") + private String buyerRemark; + + /** + * 卖家备注 + */ + @Excel(name = "卖家备注") + private String sellerRemark; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + + /** + * 订单支付成功时间 + */ + @Excel(name = "支付成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchQrCodesExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchQrCodesExportExcel.java new file mode 100644 index 0000000..f41ac62 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchQrCodesExportExcel.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 商户码牌导出 + * + * @author xiaoyu + * + * @date 2022/3/3 10:07 + */ +@Data +public class MchQrCodesExportExcel { + + @Excel(name = "码牌编号") + private String qrcId; + + @Excel(name = "批次号") + private String batchId; + + @Excel(name = "码牌名称") + private String qrcAlias; + + @Excel(name = "门店名称") + private String storeName; + + @Excel(name = "门店编号") + private String storeId; + + @Excel(name = "绑定状态", replace = {"未绑定_0", "已绑定_1"}) + private String bindState; + + @Excel(name = "是否固定支付金额", replace = {"否_0", "是_1"}) + private String fixedFlag; + + @Excel(name = "固定支付金额") + private BigDecimal fixedPayAmount; + + @Excel(name = "二维码路径") + private String qrCodeUrl; + + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchRefundOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchRefundOrderExportExcel.java new file mode 100644 index 0000000..dc64323 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchRefundOrderExportExcel.java @@ -0,0 +1,164 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 退款订单表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-04-27 + */ +@Data +public class MchRefundOrderExportExcel { + + /** + * 退款订单号(支付系统生成订单号) + */ + @Excel(name = "退款订单号") + private String refundOrderId; + + /** + * 支付订单号(与t_pay_order对应) + */ + @Excel(name = "平台单号") + private String payOrderId; + + /** + * 渠道支付单号(与t_pay_order channel_order_no对应) + */ + @Excel(name = "通道单号") + private String channelPayOrderNo; + + /** + * 渠道单号 + */ + @Excel(name = "渠道单号") + private String platformOrderNo; + + /** + * 商户单号 + */ + @Excel(name = "商户单号") + private String mchOrderNo; + + /** + * 落单号 + */ + @Excel(name = "落单号") + private String platformMchOrderNo; + + /** + * 商户简称 + */ + @Excel(name = "商户简称") + private String mchName; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchExtNo; + + /** + * 门店ID + */ + @Excel(name = "门店编号") + private String storeId; + + /** + * 门店名称 + */ + @Excel(name = "门店名称") + private String storeName; + + /** + * 应用ID + */ + @Excel(name = "应用编号") + private String appId; + + /** + * 应用名称 + */ + @Excel(name = "应用名称") + private String appName; + + /** + * 商户退款单号(商户系统的订单号) + */ + @Excel(name = "商户退款单号") + private String mchRefundNo; + + /** + * 支付通道 + */ + @Excel(name = "支付通道") + private String ifName; + + /** + * 所属渠道 + */ + @Excel(name = "所属渠道") + private String isvName; + + /** + * 支付金额 + */ + @Excel(name = "支付金额") + private BigDecimal payAmount; + + /** + * 退款金额 + */ + @Excel(name = "退款金额") + private BigDecimal refundAmount; + + /** + * 退款金额 + */ + @Excel(name = "手续费退还金额") + private BigDecimal refundFeeAmount; + + /** + * 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭 + */ + @Excel(name = "退款状态", replace = {"订单生成_0", "退款中_1", "退款成功_2", "退款失败_3", "退款任务关闭_4"}) + private String state; + + /** + * 退款类型 + */ + @Excel(name = "退款类型", replace = {"未退款_0","全额退款_1", "部分退款_2"}) + private String refundType; + + /** + * 退款类型 + */ + @Excel(name = "退款模式", replace = {"收款商户号_1","平台一般户_2"}) + private String extParam; + + /** + * 退款原因 + */ + @Excel(name = "退款原因") + private String refundReason; + + /** + * 订单退款成功时间 + */ + @Excel(name = "订单退款成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchTransferOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchTransferOrderExportExcel.java new file mode 100644 index 0000000..ed60fb6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MchTransferOrderExportExcel.java @@ -0,0 +1,98 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 转账订单表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-08-11 + */ +@Data +public class MchTransferOrderExportExcel { + + /** + * 转账订单号 + */ + @Excel(name = "转账订单号") + private String transferId; + + /** + * 应用ID + */ + @Excel(name = "应用ID") + private String appId; + + /** + * 商户订单号 + */ + @Excel(name = "商户订单号") + private String mchOrderNo; + + /** + * 支付接口代码 + */ + @Excel(name = "支付接口代码") + private String ifCode; + + /** + * 入账方式: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡 + */ + @Excel(name = "退款状态", replace = {"微信零钱_WXCASH", "支付宝转账_ALIPAYCASH", "银行卡_BANKCARD"}) + private String entryType; + + /** + * 转账金额 + */ + @Excel(name = "转账金额") + private BigDecimal amount; + + /** + * 收款账号 + */ + @Excel(name = "收款账号") + private String accountNo; + + /** + * 收款人姓名 + */ + @Excel(name = "收款人姓名") + private String accountName; + + /** + * 收款人开户行名称 + */ + @Excel(name = "收款人开户行名称") + private String bankName; + + /** + * 转账备注信息 + */ + @Excel(name = "转账备注信息") + private String transferDesc; + + /** + * 支付状态: 0-订单生成, 1-转账中, 2-转账成功, 3-转账失败, 4-订单关闭 + */ + @Excel(name = "退款状态", replace = {"订单生成_0", "转账中_1", "转账成功_2", "转账失败_3", "订单关闭_4"}) + private String state; + + /** + * 转账成功时间 + */ + @Excel(name = "转账成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MemberInfoExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MemberInfoExportExcel.java new file mode 100644 index 0000000..5c47e7d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/MemberInfoExportExcel.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.util.Date; + +/** + *

+ * 会员信息表 + *

+ * + * @since 2021-09-28 + */ +@Data +public class MemberInfoExportExcel { + + /** + * 会员ID + */ + @Excel(name = "会员ID") + private String mbrId; + + /** + * 会员名称 + */ + @Excel(name = "会员名称") + private String mbrName; + + /** + * 会员手机号 + */ + @Excel(name = "会员手机号") + private String mbrTel; + + + /** + * 账户余额 + */ + @Excel(name = "账户余额") + private String balance; + + /** + * 状态 + */ + @Excel(name = "状态", replace = {"停用_0", "启用_1"}) + private String state; + + /** + * 会员备注 + */ + @Excel(name = "会员备注") + private String remark; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/PayOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/PayOrderExportExcel.java new file mode 100644 index 0000000..398a0ee --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/PayOrderExportExcel.java @@ -0,0 +1,140 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 支付订单表 + *

+ * + * @since 2021-09-28 + */ +@Data +public class PayOrderExportExcel { + + /** + * 支付订单号 + */ + @Excel(name = "支付订单号") + private String payOrderId; + + /** + * 商户订单号 + */ + @Excel(name = "商户订单号") + private String mchOrderNo; + + /** + * 用户支付凭证交易单号 + */ + @Excel(name = "用户支付凭证交易单号") + private String platformOrderNo; + + /** + * 用户支付凭证商户单号 + */ + @Excel(name = "用户支付凭证商户单号") + private String platformMchOrderNo; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchNo; + + /** + * 商户名称 + */ + @Excel(name = "商户名称") + private String mchName; + + /** + * 门店ID + */ + @Excel(name = "门店ID") + private String storeId; + + + /** + * 门店名称 + */ + @Excel(name = "门店名称") + private String storeName; + + /** + * 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + @Excel(name = "支付状态", replace = {"订单生成_0", "支付中_1", "支付成功_2", "支付失败_3", "已撤销_4", "已退款_5", "订单关闭_6"}) + private String state; + + /** + * 退款状态: 0-未发生实际退款, 1-部分退款, 2-全额退款 + */ + @Excel(name = "退款状态", replace = {"未退款_0", "部分退款_1", "全额退款_2"}) + private String refundState; + + /** + * 服务商号 + */ + @Excel(name = "服务商号") + private String isvNo; + + /** + * 支付方式代码 + */ + @Excel(name = "支付方式") + private String wayName; + + /** + * 支付金额 + */ + @Excel(name = "支付金额") + private BigDecimal amount; + + /** + * 退款金额 + */ + @Excel(name = "退款金额") + private BigDecimal refundAmount; + + /** + * 实际手续费 + */ + @Excel(name = "实际手续费") + private BigDecimal mchFeeAmount; + + /** + * 收单手续费 + */ + @Excel(name = "收单手续费") + private BigDecimal mchOrderFeeAmount; + + /** + * 买家备注 + */ + @Excel(name = "买家备注") + private String buyerRemark; + + /** + * 卖家备注 + */ + @Excel(name = "卖家备注") + private String sellerRemark; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + + /** + * 订单支付成功时间 + */ + @Excel(name = "支付成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/RefundOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/RefundOrderExportExcel.java new file mode 100644 index 0000000..5b65415 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/RefundOrderExportExcel.java @@ -0,0 +1,134 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 退款订单表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-04-27 + */ +@Data +public class RefundOrderExportExcel { + + /** + * 退款订单号(支付系统生成订单号) + */ + @Excel(name = "退款订单号") + private String refundOrderId; + + /** + * 支付订单号(与t_pay_order对应) + */ + @Excel(name = "支付订单号") + private String payOrderId; + + /** + * 渠道支付单号(与t_pay_order channel_order_no对应) + */ + @Excel(name = "渠道支付单号") + private String channelPayOrderNo; + + /** + * 门店ID + */ + @Excel(name = "门店ID") + private String storeId; + + /** + * 门店名称 + */ + @Excel(name = "门店名称") + private String storeName; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchNo; + + /** + * 服务商号 + */ + @Excel(name = "服务商号") + private String isvNo; + + /** + * 应用ID + */ + @Excel(name = "应用ID") + private String appId; + + /** + * 商户名称 + */ + @Excel(name = "商户名称") + private String mchName; + + /** + * 商户退款单号(商户系统的订单号) + */ + @Excel(name = "商户退款单号") + private String mchRefundNo; + + /** + * 支付方式代码 + */ + @Excel(name = "支付方式代码") + private String wayCode; + + /** + * 支付接口代码 + */ + @Excel(name = "支付接口代码") + private String ifCode; + + /** + * 支付金额 + */ + @Excel(name = "支付金额") + private BigDecimal payAmount; + + /** + * 退款金额 + */ + @Excel(name = "退款金额") + private BigDecimal refundAmount; + + /** + * 退款金额 + */ + @Excel(name = "手续费退还金额") + private BigDecimal refundFeeAmount; + + /** + * 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败,4-退款任务关闭 + */ + @Excel(name = "退款状态", replace = {"订单生成_0", "退款中_1", "退款成功_2", "退款失败_3", "退款任务关闭_4"}) + private String state; + + /** + * 退款原因 + */ + @Excel(name = "退款原因") + private String refundReason; + + /** + * 订单退款成功时间 + */ + @Excel(name = "订单退款成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/SettleInfoExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/SettleInfoExportExcel.java new file mode 100644 index 0000000..6a84c54 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/SettleInfoExportExcel.java @@ -0,0 +1,116 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +public class SettleInfoExportExcel { + + /** + * 用户名称 + */ + @Excel(name = "用户名称") + private String mchUserName; + + /** + * 商户名称 + */ + @Excel(name = "商户名称") + private String mchName; + + /** + * 服务商名称 + */ + @Excel(name = "服务商名称") + private String agentName; + + /** + * 支付通道 + */ + @Excel(name = "支付通道") + private String ifName; + + /** + * 应用名称 + */ + @Excel(name = "应用名称") + private String appName; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchExtNo; + + + /** + * 结算账户名 + */ + @Excel(name = "结算账户名") + private String accountName; + + /** + *结算账户 + */ + @Excel(name = "结算卡号") + private String accountNo; + + /** + * 交易手续费 + */ + @Excel(name = "交易手续费") + private String fee; + + /** + * 垫资手续费 + */ + @Excel(name = "垫资手续费") + private String cashFee; + + /** + * 结算金额 + */ + @Excel(name = "结算金额") + private String settleAmt; + + /** + * D0 D1 T1 + */ + @Excel(name = "结算类型") + private String settleType; + + /** + * 附言信息 + */ + @Excel(name = "附言信息") + private String remark; + + /** + * 结算状态 + */ + @Excel(name = "结算状态", replace = {"付款失败_-1","待付款_0", "付款中_1", "付款成功_2", "暂缓_3", "冻结_4", "退票_5", "待查看_98", "其它_99"}) + private String state; + + /** + * 成功交易笔数 + */ + @Excel(name = "交易笔数") + private Integer transactionNumber; + + /** + * 成功交易金额 + */ + @Excel(name = "交易金额") + private Long transactionAmount; + + /** + * 结算时间 + */ + @Excel(name = "结算时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/TransferOrderExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/TransferOrderExportExcel.java new file mode 100644 index 0000000..c4eb7cd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/TransferOrderExportExcel.java @@ -0,0 +1,116 @@ +package com.jeequan.jeepay.core.model.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 转账订单表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-08-11 + */ +@Data +public class TransferOrderExportExcel { + + /** + * 转账订单号 + */ + @Excel(name = "转账订单号") + private String transferId; + + /** + * 商户号 + */ + @Excel(name = "商户号") + private String mchNo; + + /** + * 服务商号 + */ + @Excel(name = "服务商号") + private String isvNo; + + /** + * 应用ID + */ + @Excel(name = "应用ID") + private String appId; + + /** + * 商户名称 + */ + @Excel(name = "商户名称") + private String mchName; + + /** + * 商户订单号 + */ + @Excel(name = "商户订单号") + private String mchOrderNo; + + /** + * 支付接口代码 + */ + @Excel(name = "支付接口代码") + private String ifCode; + + /** + * 入账方式: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡 + */ + @Excel(name = "退款状态", replace = {"微信零钱_WXCASH", "支付宝转账_ALIPAYCASH", "银行卡_BANKCARD"}) + private String entryType; + + /** + * 转账金额 + */ + @Excel(name = "转账金额") + private BigDecimal amount; + + /** + * 收款账号 + */ + @Excel(name = "收款账号") + private String accountNo; + + /** + * 收款人姓名 + */ + @Excel(name = "收款人姓名") + private String accountName; + + /** + * 收款人开户行名称 + */ + @Excel(name = "收款人开户行名称") + private String bankName; + + /** + * 转账备注信息 + */ + @Excel(name = "转账备注信息") + private String transferDesc; + + /** + * 支付状态: 0-订单生成, 1-转账中, 2-转账成功, 3-转账失败, 4-订单关闭 + */ + @Excel(name = "退款状态", replace = {"订单生成_0", "转账中_1", "转账成功_2", "转账失败_3", "订单关闭_4"}) + private String state; + + /** + * 转账成功时间 + */ + @Excel(name = "转账成功时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date successTime; + + /** + * 创建时间 + */ + @Excel(name = "创建时间", exportFormat = "yyyy-MM-dd HH:mm:ss") + private Date createdAt; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticAgentExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticAgentExportExcel.java new file mode 100644 index 0000000..53adebc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticAgentExportExcel.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticAgentExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "服务商号", width = 15) + private String agentNo; + + @Excel(name = "服务商名称", width = 25) + private String agentName; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticBaseExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticBaseExportExcel.java new file mode 100644 index 0000000..83573b5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticBaseExportExcel.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticBaseExportExcel { + + @Excel(name = "成交金额", width = 15) + private String allAmount; + + @Excel(name = "实收金额", width = 15) + private String payAmount; + + @Excel(name = "退款金额", width = 15) + private String refundAmount; + + @Excel(name = "退款笔数", width = 15) + private String totalRefundNum; + + @Excel(name = "手续费", width = 15) + private String totalFeeAmt; + + @Excel(name = "手续费回退", width = 15) + private String totalRefundFeeAmt; + + @Excel(name = "成交笔数", width = 15) + private String totalSuccNum; + + @Excel(name = "总交易笔数", width = 15) + private String totalNum; + + @Excel(name = "成功率", width = 15) + private String round; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticChannelExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticChannelExportExcel.java new file mode 100644 index 0000000..3430fa5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticChannelExportExcel.java @@ -0,0 +1,15 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticChannelExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "通道名称", width = 25) + private String ifName; + + @Excel(name = "通道代码", width = 15) + private String ifCode; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticDeviceExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticDeviceExportExcel.java new file mode 100644 index 0000000..cb6d9c2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticDeviceExportExcel.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticDeviceExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "设备号", width = 15) + private String deviceNo; + + @Excel(name = "设备名称", width = 15) + private String deviceName; + + @Excel(name = "设备类型", width = 15) + private String deviceType; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticIsvExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticIsvExportExcel.java new file mode 100644 index 0000000..fb528f5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticIsvExportExcel.java @@ -0,0 +1,14 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticIsvExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "服务商号", width = 15) + private String isvNo; + + @Excel(name = "服务商名称", width = 25) + private String isvName; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMcMchExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMcMchExportExcel.java new file mode 100644 index 0000000..ba33be8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMcMchExportExcel.java @@ -0,0 +1,15 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticMcMchExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "商户名称", width = 25) + private String mchShortName; + + @Excel(name = "商户编号", width = 15) + private String applyId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMchExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMchExportExcel.java new file mode 100644 index 0000000..e012da2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticMchExportExcel.java @@ -0,0 +1,21 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticMchExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "商户号", width = 15) + private String mchNo; + + @Excel(name = "商户名", width = 25) + private String mchName; + + @Excel(name = "服务商号", width = 15) + private String agentNo; + + @Excel(name = "服务商号", width = 15) + private String isvNo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticStoreExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticStoreExportExcel.java new file mode 100644 index 0000000..c1d2a8d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticStoreExportExcel.java @@ -0,0 +1,15 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticStoreExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "门店编号", width = 15) + private String storeId; + + @Excel(name = "门店名称", width = 25) + private String storeName; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticTransactionExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticTransactionExportExcel.java new file mode 100644 index 0000000..ce6235b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticTransactionExportExcel.java @@ -0,0 +1,12 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticTransactionExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "日期", width = 15) + private String groupDate; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeExportExcel.java new file mode 100644 index 0000000..6d1aa45 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeExportExcel.java @@ -0,0 +1,15 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticWayCodeExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "支付方式代码", width = 15) + private String wayCode; + + @Excel(name = "支付方式名称", width = 25) + private String wayName; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeTypeExportExcel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeTypeExportExcel.java new file mode 100644 index 0000000..7dfcf4d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/export/statistic/StatisticWayCodeTypeExportExcel.java @@ -0,0 +1,15 @@ +package com.jeequan.jeepay.core.model.export.statistic; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class StatisticWayCodeTypeExportExcel extends StatisticBaseExportExcel{ + + @Excel(name = "支付类型代码", width = 15) + private String wayType; + + @Excel(name = "支付类型名称", width = 15) + private String typeName; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ip/IpAddressResult.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ip/IpAddressResult.java new file mode 100644 index 0000000..8f2703e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/ip/IpAddressResult.java @@ -0,0 +1,65 @@ +package com.jeequan.jeepay.core.model.ip; + +import com.jeequan.jeepay.core.utils.ip.AddressUtils; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * TODO + * ip解析的地址信息返回结果 + * @author crystal + * @date 2024/3/21 10:54 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class IpAddressResult implements Serializable { + + public static final byte SUCCESS = 1; + + public static final byte FAIL = -1; + + public static final byte INTERNAL = 0; + + /** + * 1:获取成功 -1 获取失败 0:内网ip: + */ + private Byte state; + + private String ip; + + private String pro; + + private String proCode; + + private String city; + + private String cityCode; + + private String region; + + private String regionCode; + + private String addr; + + private String err; + + public IpAddressResult(String ip,Byte state, String addr) { + this.ip = ip; + this.state = state; + this.addr = addr; + } + + public static IpAddressResult internal(String ip){ + IpAddressResult result = new IpAddressResult(ip,INTERNAL, AddressUtils.LOCATION_TEXT); + return result; + } + + public static IpAddressResult fail(String ip,String msg){ + IpAddressResult result = new IpAddressResult(ip,FAIL, msg); + return result; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/mchconfig/MchDivisionConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/mchconfig/MchDivisionConfig.java new file mode 100644 index 0000000..1b2cf7d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/mchconfig/MchDivisionConfig.java @@ -0,0 +1,47 @@ +package com.jeequan.jeepay.core.model.mchconfig; + +import lombok.Data; + +/** +* 商户分账设置model +* +* @author terrfly +* +* @date 2022/5/26 15:18 +*/ +@Data +public class MchDivisionConfig { + + /** + * 计算分账金额的分账基数规则: ORDER_AMOUNT-订单金额, INCOME_AMOUNT-入账金额(订单金额-手续费) + **/ + public static final String CAL_BASE_AMOUNT_TYPE_ORDER_AMOUNT = "ORDER_AMOUNT"; + public static final String CAL_BASE_AMOUNT_TYPE_INCOME_AMOUNT = "INCOME_AMOUNT"; + + /** 全局自动分账开关 */ + private Byte overrideAutoFlag; + + /** 商户拥有权限 */ + private Byte mchDivisionEntFlag; + + /** 全局自动分账规则 */ + private AutoDivisionRule autoDivisionRules; + + /** + * 计算分账金额基数的类型, 如果为空 默认为:INCOME_AMOUNT-入账金额 + */ + private String calBaseAmountType; + + /** 全局自动分账规则 */ + @Data + public static class AutoDivisionRule{ + + /** 自动分账最低金额 */ + private Long amountLimit; + + /** 延迟时间 */ + private Integer delayTime; + + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/AlipayOauth2Params.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/AlipayOauth2Params.java new file mode 100644 index 0000000..5511cf9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/AlipayOauth2Params.java @@ -0,0 +1,79 @@ +package com.jeequan.jeepay.core.model.oauth2; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/*** +* 支付宝 oauth2相关参数配置 +* +* @author terrfly +* +* @date 2022/11/9 14:27 +*/ +@Data +public class AlipayOauth2Params extends Oauth2Params{ + + /** 是否使用子商户的 小程序账号( 目前仅小程序使用 ) 1-是 0-否 **/ + private Byte isUseSubmchAccount; + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** pid */ + private String pid; + + /** appId */ + private String appId; + + /** privateKey */ + private String privateKey; + + /** alipayPublicKey */ + private String alipayPublicKey; + + /** 签名方式 **/ + private String signType; + + /** 是否使用证书方式 **/ + private Byte useCert; + + /** app 证书 **/ + private String appPublicCert; + + /** 支付宝公钥证书(.crt格式) **/ + private String alipayPublicCert; + + /** 支付宝根证书 **/ + private String alipayRootCert; + + /** 支付宝 页面路径 **/ + private String pagePath; + + /** 支付宝小程序参数 **/ + private AlipayOauth2Params liteParams; + + @Override + public String deSenData() { + + AlipayOauth2Params isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.str2Star(isvParams.privateKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(isvParams.alipayPublicKey)) { + isvParams.setAlipayPublicKey(StringKit.str2Star(isvParams.alipayPublicKey, 6, 6, 6)); + } + + AlipayOauth2Params liteExtParams = isvParams.liteParams; + if (liteExtParams != null && StringUtils.isNotBlank(liteExtParams.privateKey)) { + liteExtParams.setPrivateKey(StringKit.str2Star(liteExtParams.privateKey, 4, 4, 6)); + } + if (liteExtParams != null && StringUtils.isNotBlank(liteExtParams.alipayPublicKey)) { + liteExtParams.setAlipayPublicKey(StringKit.str2Star(liteExtParams.alipayPublicKey, 6, 6, 6)); + } + + return JSON.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/Oauth2Params.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/Oauth2Params.java new file mode 100644 index 0000000..748d1d5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/Oauth2Params.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.core.model.oauth2; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; + +/*** +* oauth2 参数定义 +* +* @author terrfly +* +* @date 2022/11/10 9:00 +*/ +public abstract class Oauth2Params { + + public static Oauth2Params factory(String ifCode, String paramsStr){ + + if(CS.IF_CODE.WXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, WxpayOauth2Params.class); + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AlipayOauth2Params.class); + } + return null; + } + + public static T factory(String ifCode, String paramsStr, Class cls){ + + if(CS.IF_CODE.WXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, cls); + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, cls); + } + return null; + } + + /** + * 敏感数据脱敏 + */ + public abstract String deSenData(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/WxpayOauth2Params.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/WxpayOauth2Params.java new file mode 100644 index 0000000..88e9b92 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/oauth2/WxpayOauth2Params.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.core.model.oauth2; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.utils.JeepayKit; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** +* 微信 oauth2相关参数 +* +* @author terrfly +* +* @date 2022/11/9 14:26 +*/ +@Data +public class WxpayOauth2Params extends Oauth2Params{ + + /** 是否使用子商户的 小程序账号( 目前仅小程序使用 ) 1-是 0-否 **/ + private Byte isUseSubmchAccount; + + /** 申请服务商的 公众号的 appID */ + private String appId; + + /** 申请服务商的 公众号应用AppSecret */ + private String appSecret; + + /** 小程序的 appID */ + private String liteAppId; + + /** 小程序的 AppSecret */ + private String liteAppSecret; + + /** 小程序的 原始ID */ + private String liteGhid; + + /** 小程序的 版本(env : release - 正式、test - 开发、 preview - 体验) */ + private String liteEnv; + + /** 小程序的 页面路径 */ + private String litePagePath; + + /** oauth2地址 */ + private String oauth2Url; + + public static final String WX_TG_PRIFEX = "https://hxj-2gb4hccs253d2569-1319126146.tcloudbaseapp.com/s.html?"+ JeepayKit.TOKEN_KEY +"="; + + @Override + public String deSenData() { + + WxpayOauth2Params isvParams = this; + if (StringUtils.isNotBlank(this.appSecret)) { + isvParams.setAppSecret(StringKit.str2Star(this.appSecret, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.liteAppSecret)) { + isvParams.setLiteAppSecret(StringKit.str2Star(this.liteAppSecret, 4, 4, 6)); + } + return ((JSONObject)JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessError.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessError.java new file mode 100644 index 0000000..a4aa931 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessError.java @@ -0,0 +1,76 @@ +package com.jeequan.jeepay.core.model.openapi; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class AccessError { + + private String code; + + private String msg; + + public static final String CODE_SUCCESS = "000000"; + + public static final AccessError SUCCESS = new AccessError(CODE_SUCCESS, "请求成功"); + + + // 定义通用code + /** + * 参数非法,主要用于限定范围的参数 + */ + public static final String CODE_ILLEGAL_PARAM_ERROR = "100001"; + + /** + * 无权限 + */ + public static final String FORBIDDEN = "100005"; + + /** + * 通用状态不正确 + */ + public static final String CODE_DATA_STATE_ERROR = "200012"; + + /** + * 签名校验失败 + */ + public static final String CODE_SIGN_CHECK_ERROR = "300001"; + + /** + * 配置异常类错误 + */ + public static final String CODE_CONFIG_ERROR = "300005"; + + /** + * 数据异常错误 + */ + public static final String CODE_DATA_GET_ERROR = "400001"; + + /** + * 通用错误码,用于一些未定义的错误类型 + */ + public static final String CODE_COMMON_ERROR = "900000"; + + public static final AccessError COMMON_DATA_ERROR = new AccessError(CODE_DATA_GET_ERROR, "数据获取失败"); + + public static final AccessError COMMON_ERROR = new AccessError(CODE_COMMON_ERROR, "系统异常,详情请咨询客服"); + + public static final AccessError SIGN_CHECK_ERROR = new AccessError(CODE_SIGN_CHECK_ERROR, "签名校验失败"); + + public static AccessError stateError(String message) { + return new AccessError(CODE_DATA_STATE_ERROR, message); + } + + public static AccessError dataError(String message) { + return new AccessError(CODE_DATA_GET_ERROR, message); + } + + public static AccessError commonError(String message) { + return new AccessError(CODE_COMMON_ERROR, message); + } + + public static AccessError configError(String message) { + return new AccessError(CODE_CONFIG_ERROR, message); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessReq.java new file mode 100644 index 0000000..8ad5bae --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessReq.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.core.model.openapi; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApp; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * TODO + * 网关api 统一请求参数封装 + * @author crystal + * @date 2024/4/7 14:28 + */ +@Data +@Accessors(chain = true) +public class AccessReq implements Serializable { + + @NotBlank(message="请求流水号[reqId]参数不能为空") + private String reqId; + + @NotBlank(message="版本[version]参数不能为空") + private String version; + + @NotBlank(message="请求时间[reqTime]参数不能为空") + private String reqTime; + + @NotBlank(message="请求签名类型[signType]参数不能为空") + private String signType; + + @NotBlank(message="签名[sign]参数不能为空") + private String sign; + + @NotBlank(message="请求业务[bizData]参数不能为空") + private String bizData; + + private JSONObject bizDataJSON; + + @NotBlank(message="应用[appId]参数不能为空") + private String appId; + + private MchApp appInfo; + + private String platPriKey; + + private String wayCode; + + private Boolean isApplet = false; + + public String signContent() { + return "appId" + "=" + appId + + "&bizData=" + bizData + + "&reqId=" + reqId + + "&reqTime=" + reqTime + + "&signType=" + signType + + "&version=" + version + ; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessResp.java new file mode 100644 index 0000000..103d5c7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/AccessResp.java @@ -0,0 +1,197 @@ +package com.jeequan.jeepay.core.model.openapi; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.entity.MchApp; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import javax.xml.bind.DatatypeConverter; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO + * 网关api统一返回参数 + * @author crystal + * @since 2024/4/7 14:32 + */ +@Slf4j +@Data +public class AccessResp implements Serializable { + + private String code; + + private String msg; + + private String timestamp; + + private String sign; + + private String signType; + + /** + * 业务响应参数 + */ + private String bizData; + + + public static AccessResp forbidden(String msg) { + AccessResp accessResp = new AccessResp(); + accessResp.setCode(AccessError.FORBIDDEN); + accessResp.setTimestamp(DateUtil.format(new Date(), "yyyyMMddHHmmss")); + accessResp.setMsg(msg); + return accessResp; + } + + public static AccessResp forbidden() { + AccessResp accessResp = new AccessResp(); + accessResp.setCode(AccessError.FORBIDDEN); + accessResp.setTimestamp(DateUtil.format(new Date(), "yyyyMMddHHmmss")); + accessResp.setMsg("无权访问"); + return accessResp; + } + + public static AccessResp fail(String code,String message) { + AccessResp accessResp = new AccessResp(); + accessResp.setCode(code); + accessResp.setTimestamp(DateUtil.format(new Date(), "yyyyMMddHHmmss")); + accessResp.setMsg(message); + + return accessResp; + } + + public static AccessResp fail(AccessReq request, Object data) { + log.error(JSON.toJSONString(data)); + return new AccessResp(AccessError.COMMON_ERROR, data, request); + } + + public static AccessResp fail(AccessReq req, String message) { + log.error(message); + Map data = new HashMap<>(); + data.put("note", message); + return new AccessResp(AccessError.commonError(message), data, req); + } + + public static AccessResp success(AccessReq req, Object data) { + return new AccessResp(AccessError.SUCCESS, data, req); + } + + + private AccessResp() {} + + @JSONField(serialize = false) + private String getSignContent() { + return "bizData=" + bizData + "&code=" + code + "&msg=" + msg + "&signType=" + signType + "×tamp=" + timestamp; + } + + public AccessResp(AccessError respEnum, Object data, AccessReq req) { + this.code = respEnum.getCode(); + this.msg = respEnum.getMsg(); + this.timestamp = DateUtil.format(new Date(), "yyyyMMddHHmmss"); + this.bizData = JSON.toJSONString(data); + MchApp appInfo = req.getAppInfo(); + String signType = req.getSignType(); + this.signType = req.getSignType(); + + if (req.getAppId() == null || appInfo == null) { + return; + } + + if (MchApp.SIGN_TYPE_MD5.equals(signType)) { + String signContent = getSignContent() + "&appSecret=" + appInfo.getAppSecret(); + this.sign = SecureUtil.md5(signContent); + this.signType = "MD5"; + return; + } else if (MchApp.SIGN_TYPE_RSA2.equals(signType)) {; + this.signType = "RSA2"; + try { + String signContent = getSignContent(); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, req.getPlatPriKey(), null); + byte[] signBytes = sign.sign(signContent); + this.sign = DatatypeConverter.printBase64Binary(signBytes); + } catch (Exception e) { + log.error("数据加签异常:", e); + log.error("加签源数据, {}", getSignContent()); + } + } else if (ObjUtil.isEmpty(signType)) { + this.signType = "RSA2"; + // 签名类型为空时,看应用中的签名配置 + List appSignTypeList = JSONArray.parseArray(appInfo.getAppSignType(), String.class); + boolean hasMD5 = false; + for (String item : appSignTypeList) { + if (item.equals("MD5")) { + hasMD5 = true; + break; + } + } + + if (hasMD5) { + this.signType = "MD5"; + String signContent = getSignContent() + "&appSecret=" + appInfo.getAppSecret(); + this.sign = SecureUtil.md5(signContent); + } else { + try { + String signContent = getSignContent(); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, req.getPlatPriKey(), null); + byte[] signBytes = sign.sign(signContent); + this.sign = DatatypeConverter.printBase64Binary(signBytes); + } catch (Exception e) { + log.error("数据加签异常:", e); + log.error("加签源数据, {}", getSignContent()); + } + } + } + + } + + public AccessResp(AccessError respEnum, Object data, String priKey, String aesKey) { + this.code = respEnum.getCode(); + this.msg = respEnum.getMsg(); + this.timestamp = DateUtil.format(new Date(), "yyyyMMddHHmmss"); + + try { + this.bizData = JSON.toJSONString(data); + String signContent = getSignContent(); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, priKey, null); + byte[] signBytes = sign.sign(signContent); + this.sign = DatatypeConverter.printBase64Binary(signBytes); + } catch (Exception e) { + log.error("数据加签异常: ", e); + log.error("加签源数据, {}", getSignContent()); + } + } + + public AccessResp(String code, String message, String priKey) { + this.code = code; + this.msg = message; + this.timestamp = DateUtil.format(new Date(), "yyyyMMddHHmmss"); + + if (priKey == null) { + return; + } + + try { + String signContent = getSignContent(); + Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, priKey, null); + byte[] signBytes = sign.sign(signContent); + this.sign = DatatypeConverter.printBase64Binary(signBytes); + } catch (Exception e) { + log.error("数据加签异常: ", e); + log.error("加签源数据, {}", getSignContent()); + } + } + + public String toJSONString() { + return JSON.toJSONString(this); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/AuditResultResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/AuditResultResp.java new file mode 100644 index 0000000..7f79a65 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/AuditResultResp.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.openapi.biz; + +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import lombok.Data; + +/** + * TODO + * + * @author deng + * @since 2024/4/22 + */ +@Data +public class AuditResultResp { + + private String applyId; + + private String subApplyId; + + private String mchInfo; + + private MchStore mchStore; + + private Byte state; + + private String remark; + + /** + * 微信商户子商户信息 + */ + private ApplymentSignInfo wxInfo; + + /** + * 支付宝子商户信息 + */ + private ApplymentSignInfo zfbInfo; + + public AuditResultResp(MchApplyment mchApplyment) { + this.applyId = mchApplyment.getApplyId(); + this.subApplyId = mchApplyment.getSubApplyId(); + this.mchInfo = mchApplyment.getApplyDetailInfo(); + this.state = mchApplyment.getState(); + + // 只把驳回的原因放进去 + if (MchApplyment.STATE_REJECT_WAIT_MODIFY == mchApplyment.getState()) { + this.remark = mchApplyment.getApplyErrorInfo(); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/PayResultResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/PayResultResp.java new file mode 100644 index 0000000..aee9447 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/PayResultResp.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.core.model.openapi.biz; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * TODO + * + * @author crystal + * @date 2024/4/10 10:47 + */ +@Data +@NoArgsConstructor +public class PayResultResp { + + protected String payOrderId; + + private String state; + + private String mchOrderNo; + + protected String ifCode; + + protected String mercNo; + + private Long amount; + + private String payType; + + protected String channelTradeNo; + + protected String channelSendNo; + +// private String wayCode; + + private String userId; + + protected String extParam; + + protected String note; + + private Long tradeFee; + + private String drType; + + private String storeId; + + private Date payTime; + + private String subject; + + private Long cashFee; + + private Long refundAmt; + + private Byte refundState; + + private String msgType; + + private String currency; + + private String settlementType; + + public PayResultResp(PayOrder order) { + this.payOrderId = order.getPayOrderId(); + this.state = CS.OpenOrderState.getVal(order.getState()).getCode(); + this.note = CS.OpenOrderState.getVal(order.getState()).getDesc(); + this.mchOrderNo = order.getMchOrderNo(); + this.ifCode = order.getIfCode(); + this.mercNo = order.getMchExtNo(); + this.amount = order.getFindAmt(); + this.payType = order.getWayCodeType(); + this.channelTradeNo = order.getPlatformOrderNo(); + this.channelSendNo = order.getPlatformMchOrderNo(); + this.userId = order.getChannelUser(); + this.extParam = order.getExtParam(); + this.drType = order.getDrType(); + this.payTime = order.getSuccessTime(); + this.subject = order.getSubject(); + this.tradeFee = order.getMchFeeAmount(); + this.cashFee = order.getCashFee(); + this.storeId = order.getStoreId(); + this.refundAmt = order.getRefundAmount(); + this.refundState = order.getRefundState(); + this.currency = order.getCurrency(); + this.settlementType = order.getSettleType(); + } + + public PayResultResp(Long amount, String mchOrderNo, String payOrderId, String state, String mchExtNo) { + this.amount = amount; + this.mchOrderNo = mchOrderNo; + this.payOrderId = payOrderId; + this.state = state; + this.mercNo = mchExtNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/RefundResultResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/RefundResultResp.java new file mode 100644 index 0000000..56c03a1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/RefundResultResp.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.core.model.openapi.biz; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * TODO + * 退款返回参数封装 + * @author crystal + * @date 2024/4/10 10:47 + */ +@Getter +@Setter +public class RefundResultResp { + + private String mchRefundNo; + + private String refundOrderId; + + private String state; + + private String oriPayOrderId; + + private String oriMchOrderNo; + + private String mercNo; + + private Long oriAmount; + + private Long refundAmt; + + private String refundReason; + + private String ifCode; + + private String note; + + private String msgType; + /** + * 退款类型 + */ + private Byte refundType; + + /** + * 退款完成时间 + */ + private Date refundTime; + + /** + * 扩展参数 + */ + private String extParam; + + /** + * 支付方式 + */ + private String payType; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizReq.java new file mode 100644 index 0000000..b3cf25c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizReq.java @@ -0,0 +1,65 @@ +package com.jeequan.jeepay.core.model.openapi.biz.app; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2024/4/12 14:56 + */ +@Data +public class AppBizReq extends UnifiedOrderRQ { + + private String payType; + + public UnifiedOrderRQ preCheck() { + if(StringUtils.isEmpty(this.getCurrency())){ + throw new ParamException("货币类型[currency]参数不能为空"); + } + if(StringUtils.isEmpty(this.getMchOrderNo())){ + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if(this.getAmount() == null || this.getAmount() < 0){ + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if(this.getMchOrderNo().length() > 32 ){ + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if(StringUtils.isEmpty(this.getSubject())){ + throw new ParamException("订单标题[subject]参数不能为空"); + } + if(StringUtils.isEmpty(this.getStoreId())){ + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if(StringUtils.isEmpty(this.getPayType())){ + throw new ParamException("支付方式[payType]参数不能为空"); + } + if(!CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType()) && !CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType())){ + throw new ParamException("支付方式[payType]参数有误"); + } + if(this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)){ + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if(StringUtils.isEmpty(this.getClientIp())){ + throw new ParamException("付款方客户端ip[clientIp]参数不能为空"); + } + if(this.getLimitPay() == null){ + this.setLimitPay(-1); + } + if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType())){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_APP); + }else if(CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType())){ + this.setWayCode(CS.PAY_WAY_CODE.WX_LITE); + }else{ + throw new ParamException("未知的支付方式[payType]参数"); + } + return this; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizResp.java new file mode 100644 index 0000000..68e9bb9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/app/AppBizResp.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.core.model.openapi.biz.app; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.openapi.biz.PayResultResp; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * TODO + * + * @author crystal + * @date 2024/4/12 14:56 + */ +@Getter +@Setter +@NoArgsConstructor +public class AppBizResp extends PayResultResp { + + private JSONObject payInfo; + + /** + * 小程序支付参数 + */ + private ChannelAppletPayMsg liteInfo; + + public AppBizResp(PayOrder order, String payUrl,ChannelAppletPayMsg liteInfo) { + super(order); + JSONObject payInfo = new JSONObject(); + payInfo.put("payUrl",payUrl); + this.payInfo = payInfo; + this.liteInfo = liteInfo; + } + + public AppBizResp(PayOrder order,String pData) { + super(order); + JSONObject payInfo = new JSONObject(); + payInfo.put("pData",pData); + this.payInfo = payInfo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/cashier/CashierBizResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/cashier/CashierBizResp.java new file mode 100644 index 0000000..e83fd4d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/cashier/CashierBizResp.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.openapi.biz.cashier; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.openapi.biz.PayResultResp; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.ChannelCashierOrderRS; +import lombok.Data; + +/** + * TODO + * + * @author crystal + * @date 2024/4/23 10:45 + */ +@Data +public class CashierBizResp extends PayResultResp { + + private JSONObject payInfo; + /** + * 小程序支付参数 + */ + private ChannelAppletPayMsg liteInfo; + + + public CashierBizResp(PayOrder order, String payUrl, ChannelAppletPayMsg liteInfo) { + super(order); + JSONObject payInfo = new JSONObject(); + payInfo.put("payUrl",payUrl); + this.payInfo = payInfo; + this.liteInfo = liteInfo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/division/DivivsionInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/division/DivivsionInfo.java new file mode 100644 index 0000000..b36ed70 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/division/DivivsionInfo.java @@ -0,0 +1,14 @@ +package com.jeequan.jeepay.core.model.openapi.biz.division; + +import lombok.Data; + +/** + * TODO + * + * @author crystal + * @date 2024/4/8 11:35 + */ +@Data +public class DivivsionInfo { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizReq.java new file mode 100644 index 0000000..1566be8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizReq.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.core.model.openapi.biz.h5; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.openapi.AccessReq; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * h5支付参数封装 + * @author crystal + * @date 2024/4/10 13:34 + */ +@Data +public class H5BizReq extends UnifiedOrderRQ { + + private String payType; + + /** + * 参数校验 + */ + public UnifiedOrderRQ preCheck() { + if(StringUtils.isEmpty(this.getCurrency())){ + throw new ParamException("货币类型[currency]参数不能为空"); + } + if(StringUtils.isEmpty(this.getMchOrderNo())){ + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if(this.getAmount() == null || this.getAmount() < 0){ + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if(this.getMchOrderNo().length() > 32 ){ + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if(StringUtils.isEmpty(this.getSubject())){ + throw new ParamException("订单标题[subject]参数不能为空"); + } + if(StringUtils.isEmpty(this.getStoreId())){ + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if(StringUtils.isEmpty(this.getPayType())){ + throw new ParamException("支付方式[payType]参数不能为空"); + } + if(!CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType()) && !CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType())){ + throw new ParamException("支付方式[payType]参数有误"); + } + if(this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)){ + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if(StringUtils.isEmpty(this.getClientIp())){ + throw new ParamException("付款方客户端ip[clientIp]参数不能为空"); + } + if(this.getLimitPay() == null){ + this.setLimitPay(-1); + } + if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType())){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_WAP); + }else if(CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType())){ + this.setWayCode(CS.PAY_WAY_CODE.WX_LITE); + }else{ + throw new ParamException("未知的支付方式[payType]参数"); + } + return this; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizResp.java new file mode 100644 index 0000000..f873e6d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/h5/H5BizResp.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.openapi.biz.h5; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.openapi.biz.PayResultResp; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +/** + * TODO + * jsapi 返回参数封装 + * @author crystal + * @date 2024/4/8 10:51 + */ +@Getter +@Setter +public class H5BizResp extends PayResultResp { + + private JSONObject payInfo; + + public H5BizResp(PayOrder order, String payUrl) { + super(order); + JSONObject payInfo = new JSONObject(); + payInfo.put("payUrl",payUrl); + this.payInfo = payInfo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5.java new file mode 100644 index 0000000..065c1df --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.openapi.biz.income; + +import lombok.Data; + +/** + * TODO + * + * @author deng + * @since 2024/4/22 + */ +@Data +public class AuditH5 { + + private String applicationId; + + private String ifCode; + + private String isvNo; + + private String range; + + private String notifyUrl; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5Resp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5Resp.java new file mode 100644 index 0000000..eb78adf --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/AuditH5Resp.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.core.model.openapi.biz.income; + +import lombok.Data; + +/** + * TODO + * + * @author deng + * @since 2024/4/22 + */ +@Data +public class AuditH5Resp { + + /** + * 系统申请单号 + */ + private String applyId; + + /** + * 下游申请单号 + */ + private String subApplyId; + + /** + * 通道编码 + */ + private String ifCode; + + /** + * 应用ID + */ + private String appId; + + /** + * 渠道号 + */ + private String isvNo; + + /** + * 进件详情页 + */ + private String detailH5Url; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/QueryApplyment.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/QueryApplyment.java new file mode 100644 index 0000000..0f8c991 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/income/QueryApplyment.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.openapi.biz.income; + +import lombok.Data; + +/** + * TODO + * + * @author deng + * @since 2024/4/22 + */ +@Data +public class QueryApplyment { + + /** + * 商户进件号 + */ + private String applyId; + + /** + * 下游申请单号 + */ + private String applicationId; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizReq.java new file mode 100644 index 0000000..97e34cc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizReq.java @@ -0,0 +1,111 @@ +package com.jeequan.jeepay.core.model.openapi.biz.jsapi; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.openapi.AccessReq; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2024/4/8 11:25 + */ +@Data +public class JsapiBizReq extends UnifiedOrderRQ { + + private String payType; + + private String userId; + + private String subAppid; + + /** + * 收款方向银联推送订单时上送的前台通知地址(仅允许为外网地址),用户完成支付点击,“返回”后,银联通过浏览器POST请求到该地址。 当transType为JSAPI,payMode为UQRCODEPAY时,可选填此字段 + */ + private String frontUrl; + + /** + * 收款方向银联推送订单时上送的前台通知地址(仅允许为外网地址),用户完成支付点击,“返回”后,银联通过浏览器POST请求到该地址。 当transType为JSAPI,payMode为UQRCODEPAY时,可选填此字段 + */ + private String frontFailUrl; + + /** + * 是否半屏 + */ + private Boolean isScreen = false; + + /** + * 参数校验 + */ + public UnifiedOrderRQ preCheck(AccessReq accessReq) { + if(StringUtils.isEmpty(this.getCurrency())){ + throw new ParamException("货币类型[currency]参数不能为空"); + } + if(StringUtils.isEmpty(this.getMchOrderNo())){ + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if(!this.getIsScreen() && StringUtils.isEmpty(this.getUserId())){ + throw new ParamException("付款用户[userId]参数不能为空"); + } + if(this.getAmount() == null || this.getAmount() < 0){ + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if(this.getMchOrderNo().length() > 32 ){ + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if(StringUtils.isEmpty(this.getSubject())){ + throw new ParamException("订单标题[subject]参数不能为空"); + } + if(StringUtils.isEmpty(this.getStoreId())){ + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if(StringUtils.isEmpty(this.getPayType())){ + throw new ParamException("支付方式[payType]参数不能为空"); + } + if(!CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType()) && !CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType()) && !CS.PAY_WAY_CODE_TYPE.UNIONPAY.equals(this.getPayType())){ + throw new ParamException("支付方式[payType]参数有误"); + } + if(this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)){ + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if(StringUtils.isEmpty(this.getClientIp())){ + throw new ParamException("付款方客户端ip[clientIp]参数不能为空"); + } + if(this.getLimitPay() == null){ + this.setLimitPay(-1); + } + JSONObject channelExtra = new JSONObject(); + channelExtra.put("userId",userId); + + if(CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(this.getPayType())){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_JSAPI); + channelExtra.put("buyerUserId",this.getUserId()); + }else if(CS.PAY_WAY_CODE_TYPE.WECHAT.equals(this.getPayType())){ + if(!this.getIsScreen() && StringUtils.isEmpty(this.getSubAppid())){ + throw new ParamException("支付类型为微信时,子商户[subAppId]参数不能为空"); + } + this.setWayCode(CS.PAY_WAY_CODE.WX_JSAPI); + channelExtra.put("openId",this.getUserId()); + channelExtra.put("subAppid",this.getSubAppid()); + }else{ + this.setWayCode(CS.PAY_WAY_CODE.YSF_JSAPI); + if(StringUtils.isNotEmpty(this.getFrontUrl())){ + channelExtra.put("frontUrl",this.getFrontUrl()); + } + if(StringUtils.isNotEmpty(this.getFrontUrl())){ + channelExtra.put("frontFailUrl",this.getFrontFailUrl()); + } + } + if(accessReq.getIsApplet()){ + this.setWayCode(this.getWayCode().replace("JSAPI","LITE")); + } + this.setChannelExtra(channelExtra.toString()); + return this; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizResp.java new file mode 100644 index 0000000..67e2c5d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/jsapi/JsapiBizResp.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.core.model.openapi.biz.jsapi; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.openapi.biz.PayResultResp; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * jsapi 返回参数封装 + * @author crystal + * @date 2024/4/8 10:51 + */ +@Setter +@Getter +public class JsapiBizResp extends PayResultResp { + + private ChannelJsapiMsg payInfo; + + private ChannelAppletPayMsg liteInfo; + + public JsapiBizResp(PayOrder order,ChannelJsapiMsg jsapiMsg) { + super(order); + this.payInfo = jsapiMsg; + } + + public JsapiBizResp(PayOrder order,ChannelAppletPayMsg liteInfo) { + super(order); + this.liteInfo = liteInfo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/micro/MicroBizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/micro/MicroBizReq.java new file mode 100644 index 0000000..a73c766 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/micro/MicroBizReq.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.core.model.openapi.biz.micro; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.openapi.AccessReq; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * + * @author crystal + * @date 2024/4/8 11:25 + */ +@Data +public class MicroBizReq extends UnifiedOrderRQ { + + private String authCode; + + private String subAppid; + + /** + * 参数校验 + */ + public UnifiedOrderRQ preCheck() { + if(StringUtils.isEmpty(this.getCurrency())){ + throw new ParamException("货币类型[currency]参数不能为空"); + } + if(StringUtils.isEmpty(this.getMchOrderNo())){ + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if(this.getAmount() == null || this.getAmount() < 0){ + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if(this.getMchOrderNo().length() > 32 ){ + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if(StringUtils.isEmpty(this.getSubject())){ + throw new ParamException("订单标题[subject]参数不能为空"); + } + if(StringUtils.isEmpty(this.getStoreId())){ + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if(this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)){ + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if(this.getLimitPay() == null){ + this.setLimitPay(-1); + } + if(StringUtils.isEmpty(this.getAuthCode())){ + throw new ParamException("付款码[authCode]参数不能为空"); + } + JSONObject channelExtra = new JSONObject(); + channelExtra.put("authCode",this.getAuthCode()); + String wayCode = JeepayKit.getPayWayCodeByBarCode(this.getAuthCode()); + if(CS.PAY_WAY_CODE.WX_BAR.equals(wayCode)){ + if(StringUtils.isEmpty(this.getSubAppid())){ + throw new ParamException("微信支付,子商户[subAppid]参数不能为空"); + } + channelExtra.put("subAppid",this.getSubAppid()); + } + this.setWayCode(wayCode); + this.setChannelExtra(channelExtra.toString()); + return this; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/query/QueryBizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/query/QueryBizReq.java new file mode 100644 index 0000000..63d79c4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/query/QueryBizReq.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.openapi.biz.query; + +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +/** + * TODO + * + * @author crystal + * @date 2024/4/10 15:49 + */ +@Data +public class QueryBizReq extends UnifiedOrderRQ { + + private String payOrderId; + + /** + * 退款流水号 + */ + private String mchRefundNo; + + /** + * 平台退款流水号 + */ + private String refundOrderId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizReq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizReq.java new file mode 100644 index 0000000..b16b625 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizReq.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.openapi.biz.scan; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +/** + * TODO + * 聚合扫码参数封装 + * @author crystal + * @date 2024/4/12 10:14 + */ +@Data +@NoArgsConstructor +public class ScanBizReq extends UnifiedOrderRQ { + + public UnifiedOrderRQ preCheck() { + if(StringUtils.isEmpty(this.getMchOrderNo())){ + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if(this.getAmount() == null || this.getAmount() < 0){ + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if(this.getMchOrderNo().length() > 32 ){ + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if(StringUtils.isEmpty(this.getSubject())){ + throw new ParamException("订单标题[subject]参数不能为空"); + } + if(StringUtils.isEmpty(this.getStoreId())){ + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if(this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)){ + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if(StringUtils.isEmpty(this.getClientIp())){ + throw new ParamException("付款方客户端ip[clientIp]参数不能为空"); + } + if(this.getLimitPay() == null){ + this.setLimitPay(-1); + } + this.setWayCode(CS.PAY_WAY_CODE.QR_CASHIER); + return this; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizResp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizResp.java new file mode 100644 index 0000000..a40d51b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/openapi/biz/scan/ScanBizResp.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.openapi.biz.scan; + +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.openapi.biz.PayResultResp; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelJsapiMsg; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * TODO + * + * @author crystal + * @date 2024/4/12 10:16 + */ +@Getter +@Setter +public class ScanBizResp extends PayResultResp { + + private ChannelJsapiMsg payInfo; + + public ScanBizResp(PayOrder payOrder,String url) { + super(payOrder); + ChannelJsapiMsg jsapiMsg = new ChannelJsapiMsg(); + jsapiMsg.setQrCodeUrl(url); + this.payInfo = jsapiMsg; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvParams.java new file mode 100644 index 0000000..82c2856 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvParams.java @@ -0,0 +1,140 @@ +package com.jeequan.jeepay.core.model.params; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.params.aliaqf.AliaqfIsvParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.model.params.allinpay.AllinpayIsvParams; +import com.jeequan.jeepay.core.model.params.bcmpay.BcmpayIsvParams; +import com.jeequan.jeepay.core.model.params.cloudpay.CloudpayIsvParams; +import com.jeequan.jeepay.core.model.params.demomockpay.DemomockpayIsvParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvParams; +import com.jeequan.jeepay.core.model.params.easypay.EasypayIsvParams; +import com.jeequan.jeepay.core.model.params.epspay.EpspayIsvParams; +import com.jeequan.jeepay.core.model.params.fbpay.FbpayIsvParams; +import com.jeequan.jeepay.core.model.params.fuioupay.FuioupayIsvParams; +import com.jeequan.jeepay.core.model.params.hkpay.HkpayIsvParams; +import com.jeequan.jeepay.core.model.params.hmpay.HmpayIsvParams; +import com.jeequan.jeepay.core.model.params.hnapay.HnapayIsvParams; +import com.jeequan.jeepay.core.model.params.icbcpay.IcbcpayIsvParams; +import com.jeequan.jeepay.core.model.params.kdbpay.KdbpayIsvParams; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvParams; +import com.jeequan.jeepay.core.model.params.leshuapay.LeshuapayIsvParams; +import com.jeequan.jeepay.core.model.params.lklpay.LklpayIsvParams; +import com.jeequan.jeepay.core.model.params.lklsb2bpay.Lklsb2bpayIsvParams; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvParams; +import com.jeequan.jeepay.core.model.params.lmspay.LmspayIsvParams; +import com.jeequan.jeepay.core.model.params.mbpay.MbpayIsvParams; +import com.jeequan.jeepay.core.model.params.pfpay.PfpayIsvParams; +import com.jeequan.jeepay.core.model.params.pmpay.PmpayIsvParams; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvParams; +import com.jeequan.jeepay.core.model.params.sftpay.SftpayIsvParams; +import com.jeequan.jeepay.core.model.params.shengpay.ShengpayIsvParams; +import com.jeequan.jeepay.core.model.params.sqbpay.SqbpayIsvParams; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvParams; +import com.jeequan.jeepay.core.model.params.terpay.TerpayIsvParams; +import com.jeequan.jeepay.core.model.params.umhspay.UmhspayIsvParams; +import com.jeequan.jeepay.core.model.params.umpay.UmpayIsvParams; +import com.jeequan.jeepay.core.model.params.utmpay.UtmpayIsvParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvParams; +import com.jeequan.jeepay.core.model.params.ysf.YsfpayIsvParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * 抽象类 isv参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + * @modify ZhuXiao + */ +@Data +public abstract class IsvParams { + + /** 结算方式 1- T1 2-D1 3-D0 */ + protected String settType; + + private static final Map> isvParamMap = new HashMap<>(); + + static { + isvParamMap.put(CS.IF_CODE.WXPAY, WxpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.ALIPAY, AlipayIsvParams.class); + isvParamMap.put(CS.IF_CODE.YSFPAY, YsfpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.SHENGPAY, ShengpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.ZFTPAY, ZftpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.SFTPAY, SftpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.HMPAY, HmpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.FUIOUPAY, FuioupayIsvParams.class); + isvParamMap.put(CS.IF_CODE.LKLPAY, LklpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.LKLSPAY, LklspayIsvParams.class); + isvParamMap.put(CS.IF_CODE.LKLSB2BPAY, Lklsb2bpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.FBPAY, FbpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.DGPAY, DgpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.PFPAY, PfpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.UTMPAY, UtmpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.SQBPAY, SqbpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.YSPAY, YspayIsvParams.class); + isvParamMap.put(CS.IF_CODE.ALLINPAY, AllinpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.MBPAY, MbpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.RYXPAY, RyxpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.TERPAY, TerpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.PMPAY, PmpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.UMPAY, UmpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.CLOUDPAY, CloudpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.HKPAY, HkpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.HNAPAY, HnapayIsvParams.class); + isvParamMap.put(CS.IF_CODE.BCMPAY, BcmpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.ICBCPAY, IcbcpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.EASYPAY, EasypayIsvParams.class); + isvParamMap.put(CS.IF_CODE.LMSPAY, LmspayIsvParams.class); + isvParamMap.put(CS.IF_CODE.LESHUAPAY, LeshuapayIsvParams.class); + isvParamMap.put(CS.IF_CODE.ALIAQF, AliaqfIsvParams.class); + isvParamMap.put(CS.IF_CODE.SXFPAY, SxfpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.EPSPAY, EpspayIsvParams.class); + isvParamMap.put(CS.IF_CODE.DEMOMOCKPAY, DemomockpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.UMHSPAY, UmhspayIsvParams.class); + isvParamMap.put(CS.IF_CODE.KDBPAY, KdbpayIsvParams.class); + isvParamMap.put(CS.IF_CODE.KQPAY, KqpayIsvParams.class); + } + + public static IsvParams factory(String ifCode, String paramsStr) { + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + Class aClass = isvParamMap.get(ifCode); + + return JSON.parseObject(paramsStr, aClass); + } + + /** + * 用于对账单下载,根据支付参数配置 获取渠道唯一渠道商号 + * 渠道是通过渠道商下载对账单时,需添加对应渠道商户号的获取 + */ + public static String getChannelIsvNo(String ifCode, IsvParams isvParams) { + + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + if (isvParams == null) { + return null; + } else if (CS.IF_CODE.WXPAY.equals(ifCode)) { + return ((WxpayIsvParams) isvParams).getMchId(); + } else if (CS.IF_CODE.SHENGPAY.equals(ifCode)) { + return ((ShengpayIsvParams) isvParams).getMchId(); + } else if (CS.IF_CODE.SXFPAY.equals(ifCode)) { + return ((SxfpayIsvParams) isvParams).getOrgId(); + } + return null; + } + + /** + * 敏感数据脱敏 + */ + public abstract String deSenData(); + + private Long altId; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvsubMchParams.java new file mode 100644 index 0000000..773474e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/IsvsubMchParams.java @@ -0,0 +1,146 @@ +package com.jeequan.jeepay.core.model.params; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.allinpay.AllinpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.bcmpay.BcmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.cloudpay.CloudpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.demomockpay.DemomockpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.easypay.EasypayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.epspay.EpspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.fbpay.FbpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.fuioupay.FuioupayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.hkpay.HkpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.hmpay.HmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.hnapay.HnapayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.icbcpay.IcbcpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.kdbpay.KdbpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.kqpay.KqpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.leshuapay.LeshuapayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.lklpay.LklpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.lklspay.LklspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.mbpay.MbpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.pfpay.PfpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.pmpay.PmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.ruipay.RyxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.sftpay.SftpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.shengpay.ShengpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.sqbpay.SqbpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.sxfpay.SxfpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.terpay.TerpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.umhspay.UmhspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.umpay.UmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.utmpay.UtmpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.ysf.YsfpayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.yspay.YspayIsvsubMchParams; +import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvsubMchParams; +import com.jeequan.jeepay.core.utils.JeepayKit; + +/* + * 抽象类 特约商户参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + */ +public abstract class IsvsubMchParams { + + public static IsvsubMchParams factory(String ifCode, String paramsStr){ + + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + if(CS.IF_CODE.WXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, WxpayIsvsubMchParams.class); + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AlipayIsvsubMchParams.class); + }else if(CS.IF_CODE.YSFPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, YsfpayIsvsubMchParams.class); + }else if(CS.IF_CODE.SHENGPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, ShengpayIsvsubMchParams.class); + }else if(CS.IF_CODE.ZFTPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, ZftpayIsvsubMchParams.class); + }else if(CS.IF_CODE.SFTPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, SftpayIsvsubMchParams.class); + }else if(CS.IF_CODE.HMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, HmpayIsvsubMchParams.class); + }else if(CS.IF_CODE.FUIOUPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, FuioupayIsvsubMchParams.class); + }else if(CS.IF_CODE.LKLPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, LklpayIsvsubMchParams.class); + }else if(CS.IF_CODE.LKLSPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, LklspayIsvsubMchParams.class); + }else if(CS.IF_CODE.FBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, FbpayIsvsubMchParams.class); + }else if(CS.IF_CODE.DGPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, DgpayIsvsubMchParams.class); + }else if(CS.IF_CODE.PFPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, PfpayIsvsubMchParams.class); + }else if(CS.IF_CODE.UTMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, UtmpayIsvsubMchParams.class); + }else if(CS.IF_CODE.SQBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, SqbpayIsvsubMchParams.class); + }else if(CS.IF_CODE.YSPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, YspayIsvsubMchParams.class); + }else if(CS.IF_CODE.RYXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, RyxpayIsvsubMchParams.class); + }else if(CS.IF_CODE.ALLINPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AllinpayIsvsubMchParams.class); + }else if(CS.IF_CODE.MBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, MbpayIsvsubMchParams.class); + }else if(CS.IF_CODE.TERPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, TerpayIsvsubMchParams.class); + }else if(CS.IF_CODE.PMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, PmpayIsvsubMchParams.class); + }else if(CS.IF_CODE.UMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, UmpayIsvsubMchParams.class); + }else if(CS.IF_CODE.CLOUDPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, CloudpayIsvsubMchParams.class); + }else if(CS.IF_CODE.HKPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, HkpayIsvsubMchParams.class); + }else if(CS.IF_CODE.HNAPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, HnapayIsvsubMchParams.class); + }else if(CS.IF_CODE.BCMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, BcmpayIsvsubMchParams.class); + }else if(CS.IF_CODE.ICBCPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, IcbcpayIsvsubMchParams.class); + }else if(CS.IF_CODE.EASYPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, EasypayIsvsubMchParams.class); + }else if(CS.IF_CODE.LESHUAPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, LeshuapayIsvsubMchParams.class); + }else if(CS.IF_CODE.ALIAQF.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AlipayIsvsubMchParams.class); + }else if(CS.IF_CODE.SXFPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, SxfpayIsvsubMchParams.class); + }else if(CS.IF_CODE.EPSPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, EpspayIsvsubMchParams.class); + }else if(CS.IF_CODE.DEMOMOCKPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, DemomockpayIsvsubMchParams.class); + } else if (CS.IF_CODE.UMHSPAY.equals(ifCode)) { + return JSONObject.parseObject(paramsStr, UmhspayIsvsubMchParams.class); + } else if (CS.IF_CODE.KDBPAY.equals(ifCode)) { + return JSONObject.parseObject(paramsStr, KdbpayIsvsubMchParams.class); + }else if(CS.IF_CODE.KQPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, KqpayIsvsubMchParams.class); + } + return null; + } + + /** + * 用于对账单下载,根据支付参数配置 获取渠道唯一 子商户号 + * 渠道是通过服务商下属子商户下载对账单时,需添加对应渠道商户号的获取 + */ + public static String getChannelMchNo(String ifCode, IsvsubMchParams isvsubMchParams){ + + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + if (isvsubMchParams == null) { + return null; + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return ((AlipayIsvsubMchParams) isvsubMchParams).getAppAuthToken(); + } + return null; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/NormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/NormalMchParams.java new file mode 100644 index 0000000..6c0ce07 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/NormalMchParams.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.core.model.params; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.params.adapay.AdapayNormalMchParams; +import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams; +import com.jeequan.jeepay.core.model.params.allinpay.AllinpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.ccbpay.CcbpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.demomockpay.DemomockpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.dgpay.DgpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.fbpay.FbpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.joinpay.JoinpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.mbpay.MbpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.pfpay.PfpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.pmpay.PmpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.pppay.PpPayNormalMchParams; +import com.jeequan.jeepay.core.model.params.sandpay.SandpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.shengpay.ShengpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.sumapay.SumapayNormalMchParams; +import com.jeequan.jeepay.core.model.params.unionpay.UnionpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.wxpay.WxpayNormalMchParams; +import com.jeequan.jeepay.core.model.params.xxpay.XxpayNormalMchParams; +import com.jeequan.jeepay.core.utils.JeepayKit; + +/* + * 抽象类 普通商户参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + */ +public abstract class NormalMchParams { + + public static NormalMchParams factory(String ifCode, String paramsStr){ + + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + if(CS.IF_CODE.WXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, WxpayNormalMchParams.class); + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AlipayNormalMchParams.class); + }else if(CS.IF_CODE.XXPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, XxpayNormalMchParams.class); + }else if(CS.IF_CODE.ADAPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AdapayNormalMchParams.class); + }else if(CS.IF_CODE.SHENGPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, ShengpayNormalMchParams.class); + }else if(CS.IF_CODE.UNIONPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, UnionpayNormalMchParams.class); + }else if(CS.IF_CODE.SANDPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, SandpayNormalMchParams.class); + }else if (CS.IF_CODE.PPPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, PpPayNormalMchParams.class); + }else if (CS.IF_CODE.PFPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, PfpayNormalMchParams.class); + }else if (CS.IF_CODE.FBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, FbpayNormalMchParams.class); + }else if (CS.IF_CODE.DGPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, DgpayNormalMchParams.class); + }else if (CS.IF_CODE.JOINPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, JoinpayNormalMchParams.class); + }else if (CS.IF_CODE.ALLINPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, AllinpayNormalMchParams.class); + }else if (CS.IF_CODE.MBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, MbpayNormalMchParams.class); + }else if (CS.IF_CODE.PMPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, PmpayNormalMchParams.class); + }else if (CS.IF_CODE.CCBPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, CcbpayNormalMchParams.class); + }else if (CS.IF_CODE.SUMAPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, SumapayNormalMchParams.class); + }else if (CS.IF_CODE.DEMOMOCKPAY.equals(ifCode)){ + return JSONObject.parseObject(paramsStr, DemomockpayNormalMchParams.class); + } + return null; + } + + /** + * 用于普通商户对账单下载,根据支付参数配置 获取渠道唯一服务商号 + */ + public static String getChannelMchNo(String ifCode, NormalMchParams normalMchParams){ + + ifCode = JeepayKit.getIfCodeOrigin(ifCode); + + if (normalMchParams == null) { + return null; + }else if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + return ((AlipayNormalMchParams) normalMchParams).getAppId(); + }else if(CS.IF_CODE.WXPAY.equals(ifCode)){ + return ((WxpayNormalMchParams) normalMchParams).getMchId(); + } + return null; + } + + /** + * 敏感数据脱敏 + */ + public abstract String deSenData(); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/adapay/AdapayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/adapay/AdapayNormalMchParams.java new file mode 100644 index 0000000..a7f2304 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/adapay/AdapayNormalMchParams.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.params.adapay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 汇付天下 配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class AdapayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** appId **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String appId; + + /** apiKey **/ + private String apiKey; + + /** rsaPrivateKey **/ + private String rsaPrivateKey; + + /** publicKey 汇付公钥**/ + private String publicKey; + + @Override + public String deSenData() { + + AdapayNormalMchParams adaParams = this; + if (StringUtils.isNotBlank(this.apiKey)) { + adaParams.setApiKey(StringKit.autoDesensitization(this.apiKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + adaParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + if (StringUtils.isNotBlank(this.rsaPrivateKey)) { + adaParams.setRsaPrivateKey(StringKit.autoDesensitization(this.rsaPrivateKey)); + } + return ((JSONObject) JSON.toJSON(adaParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvParams.java new file mode 100644 index 0000000..a52574d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvParams.java @@ -0,0 +1,165 @@ +package com.jeequan.jeepay.core.model.params.aliaqf; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.entity.TransferWallet; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 支付宝安全发 isv参数定义 + * + * @author xiaoyu + * + * @date 2023/4/3 10:10 + */ +@Data +public class AliaqfIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** pid */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String pid; + + /** appId */ + private String appId; + + /** privateKey */ + private String privateKey; + + /** alipayPublicKey */ + private String alipayPublicKey; + + /** 签名方式 **/ + private String signType; + + /** 是否使用证书方式 **/ + private Byte useCert; + + /** app 证书 **/ + private String appPublicCert; + + /** 支付宝公钥证书(.crt格式) **/ + private String alipayPublicCert; + + /** 支付宝根证书 **/ + private String alipayRootCert; + + /** + * (下级模板)到支付宝月限额(分) + */ + private String subZfbMonthMax; + + /** + * (下级模板)到支付宝日限额(分) + */ + private String subZfbDayMax; + + /** + * (下级模板)个人支付宝单笔限额(分) + */ + private String subZfbPriOnceMax; + + /** + * (下级模板)企业支付宝单笔限额(分) + */ + private String subZfbCorOnceMax; + + /** + * (下级模板)到银行卡月限额(分) + */ + private String subBankCardMonthMax; + + /** + * (下级模板)到银行卡日限额(分) + */ + private String subBankCardDayMax; + + /** + * (下级模板)到对私银行卡单笔限额(分) + */ + private String subBankCardPriOnceMax; + + /** + * (下级模板)到对公银行卡单笔限额(分) + */ + private String subBankCardCorOnceMax; + + /** + * (总)到支付宝月限额(分) + */ + private String zfbMonthMax; + + /** + * (总)到支付宝日限额(分) + */ + private String zfbDayMax; + + /** + * (总)个人支付宝单笔限额(分) + */ + private String zfbPriOnceMax; + + /** + * (总)企业支付宝单笔限额(分) + */ + private String zfbCorOnceMax; + + /** + * (总)到银行卡月限额(分) + */ + private String bankCardMonthMax; + + /** + * (总)到银行卡日限额(分) + */ + private String bankCardDayMax; + + /** + * (总)到对私银行卡单笔限额(分) + */ + private String bankCardPriOnceMax; + + /** + * (总)到对公银行卡单笔限额(分) + */ + private String bankCardCorOnceMax; + + @Override + public String deSenData() { + + AliaqfIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.alipayPublicKey)) { + isvParams.setAlipayPublicKey(StringKit.autoDesensitization(isvParams.alipayPublicKey)); + } + + return JSON.toJSONString(isvParams); + } + + /** + * 配置额度 + * @param wallet + */ + public void initQuota(TransferWallet wallet) { + wallet.setWxMonthMax(0L); + wallet.setWxDayMax(0L); + wallet.setWxPriOnceMax(0L); + wallet.setWxCorOnceMax(0L); + wallet.setBankCardCorOnceMax(Long.parseLong(getSubBankCardCorOnceMax())); + wallet.setBankCardPriOnceMax(Long.parseLong(getSubBankCardPriOnceMax())); + wallet.setBankCardMonthMax(Long.parseLong(getSubBankCardMonthMax())); + wallet.setBankCardDayMax(Long.parseLong(getSubBankCardDayMax())); + wallet.setZfbCorOnceMax(Long.parseLong(getSubZfbCorOnceMax())); + wallet.setZfbPriOnceMax(Long.parseLong(getSubZfbPriOnceMax())); + wallet.setZfbMonthMax(Long.parseLong(getSubZfbMonthMax())); + wallet.setZfbDayMax(Long.parseLong(getSubZfbDayMax())); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvsubMchParams.java new file mode 100644 index 0000000..cc85ed3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/aliaqf/AliaqfIsvsubMchParams.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model.params.aliaqf; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 支付宝安全发 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2023/4/3 10:11 + */ +@Data +public class AliaqfIsvsubMchParams extends IsvsubMchParams { + + /** 签约协议编号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String agreementNo; + + /** 记账本ID **/ + private String accountBookId; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayConfig.java new file mode 100644 index 0000000..e4a03dc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayConfig.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.params.alipay; + +import lombok.Data; + +/* +* 支付宝, 通用配置信息 +* +* @author terrfly +* +* @date 2021/6/8 16:32 +*/ +@Data +public class AlipayConfig { + + public static final String SIGN_TYPE_RSA = "RSA"; + public static final String SIGN_TYPE_RSA2 = "RSA2"; + + + /** 网关地址 */ + public static String PROD_SERVER_URL = "https://openapi.alipay.com/gateway.do"; + public static String SANDBOX_SERVER_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do"; + + public static String PROD_OAUTH_URL = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=%s&scope=auth_base&state=&redirect_uri=%s"; + public static String SANDBOX_OAUTH_URL = "https://openapi-sandbox.dl.alipaydev.com/oauth2/publicAppAuthorize.htm?app_id=%s&scope=auth_base&state=&redirect_uri=%s"; + + /** isv获取授权商户URL地址 **/ + public static String PROD_APP_TO_APP_AUTH_URL = "https://openauth.alipay.com/oauth2/appToAppAuth.htm?app_id=%s&redirect_uri=%s&state=%s"; + public static String SANDBOX_APP_TO_APP_AUTH_URL = "https://openapi-sandbox.dl.alipaydev.com/oauth2/appToAppAuth.htm?app_id=%s&redirect_uri=%s&state=%s"; + + + public static String FORMAT = "json"; + + public static String CHARSET = "UTF-8"; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvParams.java new file mode 100644 index 0000000..d992a03 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvParams.java @@ -0,0 +1,92 @@ +package com.jeequan.jeepay.core.model.params.alipay; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 支付宝 isv参数定义 +* +* @author terrfly +* +* @date 2021/6/8 16:34 +*/ +@Data +public class AlipayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** pid */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String pid; + + /** appId */ + private String appId; + + /** privateKey */ + private String privateKey; + + /** alipayPublicKey */ + private String alipayPublicKey; + + /** 签名方式 **/ + private String signType; + + /** 是否使用证书方式 **/ + private Byte useCert; + + /** app 证书 **/ + private String appPublicCert; + + /** 支付宝公钥证书(.crt格式) **/ + private String alipayPublicCert; + + /** 支付宝根证书 **/ + private String alipayRootCert; + + /** 授权token */ + private String appAuthToken; + + + @Override + public String deSenData() { + + AlipayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.str2Star(isvParams.privateKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(isvParams.alipayPublicKey)) { + isvParams.setAlipayPublicKey(StringKit.str2Star(isvParams.alipayPublicKey, 6, 6, 6)); + } + + return JSONObject.toJSONString(isvParams); + } + + @JSONField(serialize = false) + public com.alipay.api.AlipayConfig getConfig() { + com.alipay.api.AlipayConfig alipayConfig = new com.alipay.api.AlipayConfig(); + alipayConfig.setServerUrl(AlipayConfig.PROD_SERVER_URL); + alipayConfig.setPrivateKey(privateKey); + alipayConfig.setAppId(appId); + alipayConfig.setCharset(AlipayConfig.CHARSET); + alipayConfig.setFormat(AlipayConfig.FORMAT); + alipayConfig.setSignType(signType); + + if (useCert == CS.YES) { + alipayConfig.setAppCertPath(appPublicCert); + alipayConfig.setAlipayPublicCertPath(alipayPublicCert); + alipayConfig.setRootCertPath(alipayRootCert); + } else { + alipayConfig.setAlipayPublicKey(alipayPublicKey); + } + + return alipayConfig; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvsubMchParams.java new file mode 100644 index 0000000..7d1a338 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayIsvsubMchParams.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.alipay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 支付宝 特约商户参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + */ +@Data +public class AlipayIsvsubMchParams extends IsvsubMchParams { + + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String appAuthToken; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayNormalMchParams.java new file mode 100644 index 0000000..ce3fc4f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/alipay/AlipayNormalMchParams.java @@ -0,0 +1,63 @@ +package com.jeequan.jeepay.core.model.params.alipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 支付宝 普通商户参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + */ +@Data +public class AlipayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** appId */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String appId; + + /** privateKey */ + private String privateKey; + + /** alipayPublicKey */ + private String alipayPublicKey; + + /** 签名方式 **/ + private String signType; + + /** 是否使用证书方式 **/ + private Byte useCert; + + /** app 证书 **/ + private String appPublicCert; + + /** 支付宝公钥证书(.crt格式) **/ + private String alipayPublicCert; + + /** 支付宝根证书 **/ + private String alipayRootCert; + + @Override + public String deSenData() { + + AlipayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + mchParams.setPrivateKey(StringKit.str2Star(this.privateKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.alipayPublicKey)) { + mchParams.setAlipayPublicKey(StringKit.str2Star(this.alipayPublicKey, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvParams.java new file mode 100644 index 0000000..70f7ae1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvParams.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.allinpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商配置参数 + * + * @author xiaoyu + * + * @date 2022/9/13 15:39 + */ +@Data +public class AllinpayIsvParams extends IsvParams { + + /** 环境配置 1-沙箱环境 0-生产环境 **/ + private Byte sandbox; + + /** 签名类型 RSA2 SM2 **/ + private String signType; + + /** 服务商id */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String orgid; + + /** appid */ + private String appId; + + /** 银联pid */ + private String unpid; + + /** 拓展人 */ + private String expandUser; + + /** 应用私钥 **/ + private String privateKey; + + /** 通联公钥 **/ + private String publicKey; + + @Override + public String deSenData() { + + AllinpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvsubMchParams.java new file mode 100644 index 0000000..eedbb30 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayIsvsubMchParams.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.allinpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/9/13 15:43 + */ +@Data +public class AllinpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 cusid**/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String cusid; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayNormalMchParams.java new file mode 100644 index 0000000..ae22f1e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/allinpay/AllinpayNormalMchParams.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.params.allinpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 普通商户参数定义 + * + * @author xiaoyu + * + * @date 2022/9/14 9:57 + */ +@Data +public class AllinpayNormalMchParams extends NormalMchParams { + + /** 环境配置 1-沙箱环境 0-生产环境 **/ + private Byte sandbox; + + /** 签名类型 RSA SM2 **/ + private String signType; + + /** 商户ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String cusid; + + /** appid */ + private String appId; + + /** 应用私钥 **/ + private String privateKey; + + /** 通联公钥 **/ + private String publicKey; + + @Override + public String deSenData() { + + AllinpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(mchParams.privateKey)) { + mchParams.setPrivateKey(StringKit.autoDesensitization(mchParams.privateKey)); + } + if (StringUtils.isNotBlank(mchParams.publicKey)) { + mchParams.setPublicKey(StringKit.autoDesensitization(mchParams.publicKey)); + } + + return JSONObject.toJSONString(mchParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvParams.java new file mode 100644 index 0000000..8a18d47 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvParams.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.bcmpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商配置参数 + * + * @author xiaoyu + * + * @date 2022/12/15 9:40 + */ +@Data +public class BcmpayIsvParams extends IsvParams { + + /** 环境配置 1-沙箱环境 0-生产环境 **/ + private Byte sandbox; + + /** partnerId */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String partnerId; + + /** APP_ID */ + private String appId; + + /** 公众号appid **/ + private String wxAppId; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 应用私钥 **/ + private String privateKey; + + /** 交行公钥 **/ + private String publicKey; + + @Override + public String deSenData() { + + BcmpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvsubMchParams.java new file mode 100644 index 0000000..458f92b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/bcmpay/BcmpayIsvsubMchParams.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.bcmpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/9/13 15:43 + */ +@Data +public class BcmpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 mcht_id**/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchtId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayConfig.java new file mode 100644 index 0000000..c89ac32 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayConfig.java @@ -0,0 +1,21 @@ +package com.jeequan.jeepay.core.model.params.ccbpay; + +import lombok.Data; + +/* + * 建行龙支付, 通用配置信息 + * + * @author zx + * + * @date 2021/12/1 10:32 + */ +@Data +public class CcbpayConfig { + + /** 网关地址 */ + public static String SERVER_URL = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6&"; + + /** 条码支付网关地址 */ + public static String SERVER_URL_BAR = "https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_00_BEPAY?"; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayNormalMchParams.java new file mode 100644 index 0000000..f26cd0d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ccbpay/CcbpayNormalMchParams.java @@ -0,0 +1,98 @@ +package com.jeequan.jeepay.core.model.params.ccbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 建行龙支付 配置参数 + * + * @author zx + * + * @date 2022/11/23 18:02 + */ +@Data +public class CcbpayNormalMchParams extends NormalMchParams { + + public static byte MER_FLAG_ONLINE = 1; + public static byte MER_FLAG_OFFLINE = 2; + + /** + * 商户类型:1-线上商户,2-线下商户 + */ + private Byte merFlag; + + /** + * 商户代码 + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantId; + + /** + * 商户柜台代码 + */ + private String posId; + + /** + * 分行代码 + */ + private String branchId; + + /** + * 商户公钥 + */ + private String publicKey; + + /** + * 外联平台接口地址 + */ + private String wlptServerUrl; + + /** + * 操作员号 + */ + private String userId; + + /** + * 操作员密码 + */ + private String password; + + /** + * 终端编号1,线下商户类型必填,联系开立商户的分行提供 + */ + private String termNo1; + + /** + * 终端编号2,线下商户类型必填,联系开立商户的分行提供 + */ + private String termNo2; + + /** + * 公众号appId + */ + private String mpAppId; + + /** + * 小程序appId + */ + private String microAppId; + + @Override + public String deSenData() { + CcbpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.publicKey)) { + mchParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + if (StringUtils.isNotBlank(this.password)) { + mchParams.setPassword(StringKit.autoDesensitization(this.password)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayConfig.java new file mode 100644 index 0000000..31090e3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayConfig.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.cibpay; + +/** + * 兴业配置 + * + * @author 独孤伶俜 + * @site jschpay + * @date 2023年04月26日11:28:43 + */ +public class CibpayConfig { + public static String BASE_URL_PAY = "https://open.cibfintech.com"; // 支付正式域名 + public static String BASE_URL_PAY_TEST = "https://open.test.cibfintech.com"; // 支付测试域名 + + + + + public static String getPayBaseUrl(Byte sandBox) { + return sandBox == null || sandBox == 0 ? BASE_URL_PAY : BASE_URL_PAY_TEST; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvParams.java new file mode 100644 index 0000000..ad71d14 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvParams.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.core.model.params.cibpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 兴业银行 服务商配置 + * + * @author zx + * + * @date 2023/5/30 10:09 + */ +@Data +public class CibpayIsvParams extends IsvParams { + + /** 是否沙箱环境 1-是 */ + private Byte sandbox; + + /** + * 响应报文验签开关,1-将进行验签,0-不进行验签 + */ + private Byte respSignSwitch; + + /** KeyId **/ + private String keyId; + + /** PriKey **/ + private String priKey; + + /** RespPubKey **/ + private String respPubKey; + + /** ReqParamEncryptKey + * 字段加密密钥 + * */ + private String reqParamEncryptKey; + + /** 微信公众号appid **/ + private String wxSubAppid; + + /** 微信小程序appid **/ + private String wxLiteSubAppid; + + + + @Override + public String deSenData() { + + CibpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.priKey)) { + isvParams.setPriKey(StringKit.autoDesensitization(this.priKey)); + } + if (StringUtils.isNotBlank(this.respPubKey)) { + isvParams.setRespPubKey(StringKit.autoDesensitization(this.respPubKey)); + } + if (StringUtils.isNotBlank(this.reqParamEncryptKey)) { + isvParams.setReqParamEncryptKey(StringKit.autoDesensitization(this.reqParamEncryptKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvsubMchParams.java new file mode 100644 index 0000000..735f8a7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cibpay/CibpayIsvsubMchParams.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.params.cibpay; + +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 兴业银行 特约商户配置 + * + * @author zx + * + * @date 2023/5/30 10:09 + */ +@Data +public class CibpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 **/ + private String mchId; + + /** 微信公众号appid **/ + private String wxSubAppid; + + /** 微信小程序appid **/ + private String wxLiteSubAppid; + + /** 商户收款APP终端编号 **/ + private String terminalInfoTerminalId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayConfig.java new file mode 100644 index 0000000..0f7c5e5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayConfig.java @@ -0,0 +1,103 @@ +package com.jeequan.jeepay.core.model.params.cloudpay; + +/** + * @author yangjun + * @version CloudpayConfig.java, v 0.1 2022-09-27 21:14 yangjun + */ +public class CloudpayConfig { + + /** + * 重复核销-标识 + */ + public static final String ERROR_VERIFY = "USED_REDEEM_CODE"; + + /** + * 网关成功code + */ + public static final String GW_CODE_SUCCESS = "10000"; + + /** + * 系统未知异常(下层功能域调用失败) 需要轮询 + */ + public static final String GW_CODE_QUERY = "20000"; + + /** + * 业务结果:01 查询成功 + */ + public static final String RESULT_CODE_SUCCESS = "01"; + /** + * 业务结果:02 查询失败 + */ + public static final String RESULT_CODE_FAIL = "02"; + /** + * 01成功 + */ + public static final String PAY_SUCCESS = "01"; + /** + * 02失败 + */ + public static final String PAY_FAIL = "02"; + /** + * 03支付中 + */ + public static final String PAY_ING = "03"; + /** + * 99该条码暂不支持支付类型自动匹配 + */ + public static final String PAY_ERROR = "99"; + + /** + * 订单状态 + */ + public static final String ORDER_SUCCESS = "ORDER_SUCCESS"; + public static final String ORDER_CLOSED = "ORDER_CLOSED"; + public static final String WAIT_PAY = "WAIT_PAY"; + /** + * 退款订单状态 + * REFUND_INIT:退款中 + * REFUND_SUCCESS:退款成功 + * REFUND_FAIL:退款失败 + */ + public static final String ORDER_REFUND_SUCCESS = "REFUND_SUCCESS"; + public static final String ORDER_REFUND_FAIL = "REFUND_FAIL"; + public static final String ORDER_REFUND_REFUNDING = "REFUND_INIT"; + /** + * 云支付请求地址 + */ + public static String PROD_SERVER_URL = "https://ecogateway.alipay-eco.com/gateway.do"; + public static String SANDBOX_SERVER_URL = "http://ecogatewaysit.alipay-eco.com/gateway.do"; + /** + * 刷卡支付 + */ + public static String BAR_CODE_PAY = "ant.antfin.eco.cloudpay.trade.pay"; + public static String TRADE_CREATE_PAY = "ant.antfin.eco.cloudpay.trade.create"; + /** + * 订单查询 + */ + public static String ORDER_QUERY = "ant.antfin.eco.cloudpay.trade.query"; + /** + * 退款申请 + */ + public static String ORDER_REFUND = "ant.antfin.eco.cloudpay.trade.refund"; + /** + * 退款查询 + */ + public static String ORDER_QUERY_REFUND = "ant.antfin.eco.cloudpay.trade.refund.query"; + /** + * 多维度订单列表查询 + */ + public static String ORDER_LIST_QUERY = "ant.antfin.eco.cloudpay.trade.batchquery"; + /** + * 多维度订单汇总查询 + */ + public static String ORDER_TOTAL_QUERY = "ant.antfin.eco.cloudpay.trade.summary"; + /** + * 云支付线上订单核销 + */ + public static String REDEEM_CODE_VERIFY = "ant.antfin.eco.cloudpayprod.redeem.code.verify"; + + /** + * 云支付退款通知标识 + */ + public static final String TRADE_TYPE_REFUND_MARK = "REFUND_SYNC"; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvParams.java new file mode 100644 index 0000000..5ec7153 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvParams.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.cloudpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * @author yangjun + * @version CloudpayIsvParam.java, v 0.1 2022-09-27 21:13 yangjun + */ +@Data +public class CloudpayIsvParams extends IsvParams { + + /** + * 是否沙箱环境 + */ + private Byte sandbox; + + /** + * 云支付分配给开发者的应用ID + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String bAppId; + + /** + * 网关加签私钥 + */ + private String priKey; + + /** + * 网关验签公钥 + */ + private String pubKey; + + /** + * 公众号appid + **/ + private String wxAppid; + + /** + * 小程序appid + **/ + private String wxLiteAppid; + + @Override + public String deSenData() { + CloudpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.priKey)) { + isvParams.setPriKey(StringKit.str2Star(isvParams.priKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(isvParams.pubKey)) { + isvParams.setPubKey(StringKit.str2Star(isvParams.pubKey, 6, 6, 6)); + } + return JSONObject.toJSONString(isvParams); + } +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvsubMchParams.java new file mode 100644 index 0000000..39ca912 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/cloudpay/CloudpayIsvsubMchParams.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model.params.cloudpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * @author yangjun + * @version CloudpayIsvsubMchParams.java, v 0.1 2022-09-27 21:13 yangjun + */ +@Data +public class CloudpayIsvsubMchParams extends IsvsubMchParams { + + /** + * 云支付商户id + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String cpMid; + + /** + * 云支付商户门店编号 + */ + private String cpStoreId; + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvParams.java new file mode 100644 index 0000000..e43b0ae --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvParams.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.params.demomockpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +/*** + * demomockpay 【本地模拟支付通道】 + * + * @author terrfly + * + * @date 2023/7/7 16:10 + */ +@Data +public class DemomockpayIsvParams extends IsvParams { + + private String accountId; + + @Override + public String deSenData() { + return JSONObject.toJSONString(this); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvsubMchParams.java new file mode 100644 index 0000000..62568ca --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayIsvsubMchParams.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.core.model.params.demomockpay; + +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/*** + * demomockpay 【本地模拟支付通道】 + * + * @author terrfly + * + * @date 2023/7/7 16:10 + */ +@Data +public class DemomockpayIsvsubMchParams extends IsvsubMchParams { + + private Integer paySuccessTime; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayNormalMchParams.java new file mode 100644 index 0000000..fa20806 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/demomockpay/DemomockpayNormalMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.demomockpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import lombok.Data; + +/*** + * demomockpay 【本地模拟支付通道】 + * + * @author terrfly + * + * @date 2023/7/7 16:10 + */ +@Data +public class DemomockpayNormalMchParams extends NormalMchParams { + + + private Integer paySuccessTime; + + + @Override + public String deSenData() { + return JSONObject.toJSONString(this); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvParams.java new file mode 100644 index 0000000..35ce451 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvParams.java @@ -0,0 +1,99 @@ +package com.jeequan.jeepay.core.model.params.dgpay; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 汇付 斗拱 配置信息 + * + * @author xiaoyu + * + * @date 2022/6/6 10:31 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class DgpayIsvParams extends IsvParams { + + /** 支付场景类型 1.线下,2.线上 **/ + private String payScene; + + /** 商户手取现类型 0-关闭 T1-下工作日 D1-下自然日 D0-当日 **/ + private String mchSettManual; + + /** 商户取现费率 % **/ + private String cashFee; + + /** 结算 D1-下自然日 T1-下工作日 **/ + private String settleCycle; + + /** 结算D1费率 % **/ + private String settleFee; + + /** 系统号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String sysId; + + /** 产品ID PAYUN、EDUSTD **/ + private String productId; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** + * 汇付服务商渠道号,与微信支付宝渠道号无关 + */ + private String channelNo; + + /** 微信渠道号(汇付自定义,指定线上或线下支付场景时必填) */ + private String wxChannelNo; + + private String zfbChannelNo; + + /** 电子协议 协议模板号 */ + private String agreementModel; + + /** 电子协议 协议模板名称 */ + private String agreementName; + + /** rsaPrivateKey **/ + private String rsaPrivateKey; + + /** publicKey 汇付公钥 **/ + private String rsaPublicKey; + + /** posPrivateKey 终端秘钥 **/ + private String webhookPrivateKey; + + /** 智能POS公钥 **/ + private String posPublicKey; + + @Override + public String deSenData() { + + DgpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.rsaPrivateKey)) { + isvParams.setRsaPrivateKey(StringKit.autoDesensitization(isvParams.rsaPrivateKey)); + } + if (StringUtils.isNotBlank(isvParams.rsaPublicKey)) { + isvParams.setRsaPublicKey(StringKit.autoDesensitization(isvParams.rsaPublicKey)); + } + if (StringUtils.isNotBlank(isvParams.webhookPrivateKey)) { + isvParams.setWebhookPrivateKey(StringKit.autoDesensitization(isvParams.webhookPrivateKey)); + } + if (StringUtils.isNotBlank(isvParams.posPublicKey)) { + isvParams.setPosPublicKey(StringKit.autoDesensitization(isvParams.posPublicKey)); + } + + return JSON.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvsubMchParams.java new file mode 100644 index 0000000..b5c6953 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayIsvsubMchParams.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.params.dgpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 汇付 斗拱 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/6/6 10:31 + */ +@Data +public class DgpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 huifu_id**/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String huifuId; + + /** 支付场景类型 **/ + private String payScene; + + /** 取现卡序列号 **/ + private String tokenNo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayNormalMchParams.java new file mode 100644 index 0000000..9de7035 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/dgpay/DgpayNormalMchParams.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.core.model.params.dgpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 汇付 斗拱 配置信息 + * + * @author xiaoyu + * + * @date 2022/6/6 10:31 + */ +@Data +public class DgpayNormalMchParams extends NormalMchParams { + + /** 商户号 huifu_id**/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String huifuId; + + /** 产品ID **/ + private String productId; + + /** rsaPrivateKey **/ + private String rsaPrivateKey; + + /** publicKey 汇付公钥 **/ + private String rsaPublicKey; + + /** 支付场景类型 **/ + private String payScene; + + @Override + public String deSenData() { + + DgpayNormalMchParams params = this; + if (StringUtils.isNotBlank(this.rsaPublicKey)) { + params.setRsaPublicKey(StringKit.autoDesensitization(this.rsaPublicKey)); + } + if (StringUtils.isNotBlank(this.rsaPrivateKey)) { + params.setRsaPrivateKey(StringKit.autoDesensitization(this.rsaPrivateKey)); + } + return ((JSONObject) JSON.toJSON(params)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvParams.java new file mode 100644 index 0000000..071c049 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvParams.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.core.model.params.easypay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 易生支付 服务商参数定义 + * + * @author yr + * + * @date 2023/01/03 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class EasypayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 结算方式 1-T1 2-D1 3-D0 */ + private String settType; + + /** D0(实时入账)默认扣率,最小值为0.01) */ + private String calcVal; + + /** 交易机构号(客户编号) */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String orgId; + + /** 交易私钥 */ + private String privateKey; + + /** 交易公钥 */ + private String publicKey; + + /** 进件机构号 */ + private String clientCode; + + /** 渠道秘钥 */ + private String agentSignKey; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + /** 支付宝appId-支付宝PID(如果不填,默认使用易生支付的) */ + private String aliAppId; + + /** 服务商微信渠道号(仅用于微信商户简称及客服号码修改) */ + private String wxChannelId; + + + @Override + public String deSenData() { + EasypayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + }if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvsubMchParams.java new file mode 100644 index 0000000..7bee5c1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/easypay/EasypayIsvsubMchParams.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.params.easypay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 易生支付 特约商户参数定义 + * + * @author yr + * + * @date 2023/01/03 + */ +@Data +public class EasypayIsvsubMchParams extends IsvsubMchParams { + + /** 结算方式 1- T1 2-D1 3-D0 0-取服务商配置 */ + private String settType; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String orgMerCode; + + /** 终端号 */ + private String orgTermNo; + + /** 微信子商户号 */ + private String wechatId; + + + + public String deSenData() { + EasypayIsvsubMchParams easypayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(easypayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvParams.java new file mode 100644 index 0000000..f896d54 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvParams.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.core.model.params.epspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 易票联 服务商参数定义 + * + * @author yr + * + * @date 2023/03/27 + */ +@Data +public class EpspayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + /** 用户公钥证书 */ + private String publicKey; + /** 用户私钥证书 */ + private String privateKey; + /** 私钥文件保护密码 */ + private String privateKeyPwd; + /** 签名证书序列号 */ + private String signNo; + + /** 平台商户编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String acqSpId; + /** 平台商户微信渠道号 */ + private String wechatChannelId; + /** 平台商户支付宝渠道商 PID */ + private String alipayChannelId; + + /** + * 结算周期 + **/ + public String settleWay; + /** 节假日垫资费率方式 0:按单笔收费;1:按比例收费;结算周期 D+1 时有效 **/ + private Byte holidayType; + /** D1 交易节假日附加收费的费率(只填数值,例如0.01) 上送时上送100*/ + private String holidayRate; + /** D1 交易节假日附加收费的单笔加收费用 */ + private String holidayPer; + + /** 微信开户意愿地址 */ + private String wxUrl; + /** 支付宝商家认证地址 */ + private String aliUrl; + + + @Override + public String deSenData() { + EpspayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKeyPwd)) { + isvParams.setPrivateKeyPwd(StringKit.autoDesensitization(isvParams.privateKeyPwd)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvsubMchParams.java new file mode 100644 index 0000000..9b36389 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/epspay/EpspayIsvsubMchParams.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.params.epspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 易票联 特约商户参数定义 + * + * @author yr + * + * @date 2023/3/27 9:06 + */ +@Data +public class EpspayIsvsubMchParams extends IsvsubMchParams { + + /** 商户编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String customerCode; + + /** + * 商户经营地区 + */ + private String areaInfo; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + public String deSenData() { + EpspayIsvsubMchParams epspayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(epspayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayConfig.java new file mode 100644 index 0000000..9f3a0b1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayConfig.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.params.fbpay; + +import lombok.Data; + +/** + * 付呗 通用配置信息 + * + * @author xiaoyu + * + * @date 2022/5/13 10:19 + */ +@Data +public class FbpayConfig { + + /** 网关地址 */ + public static String PROD_SERVER_URL = "https://shq-api.51fubei.com/gateway/agent"; + + /** 上游返回订单状态 SUCCESS-成功 USERPAYING-支付中 **/ + public static final String ORDER_STATE_SUCCESS = "SUCCESS"; + public static final String ORDER_STATE_ING = "USERPAYING"; + public static final String ORDER_STATE_CLOSED = "CLOSED"; + + /** 上游返回退款状态 REFUND_PROCESSING-退款中 REFUND_SUCCESS-退款成功 REFUND_FAIL-退款失败 **/ + public static final String REFUND_STATE_ING = "REFUND_PROCESSING"; + public static final String REFUND_STATE_SUCCESS = "REFUND_SUCCESS"; + public static final String REFUND_STATE_FAIL = "REFUND_FAIL"; + + /** 支付接口 **/ + public static final String INTERFACE_TYPE_ORDER_PAY = "fbpay.order.pay"; // 付款码支付 + public static final String INTERFACE_TYPE_ORDER_CREATE = "fbpay.order.create"; // 统一下单 + public static final String INTERFACE_TYPE_ORDER_QUERY = "fbpay.order.query"; // 订单查询 + public static final String INTERFACE_TYPE_ORDER_CLOSE = "fbpay.order.close"; // 订单关闭 + public static final String INTERFACE_TYPE_ORDER_REFUND = "fbpay.order.refund"; // 退款 + public static final String INTERFACE_TYPE_ORDER_REFUND_QUERY = "fbpay.order.refund.query"; // 退款查询 + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvParams.java new file mode 100644 index 0000000..53a9cb8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvParams.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.params.fbpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 付呗 isv参数定义 + * + * @author xiaoyu + * + * @date 2022/5/13 10:27 + */ +@Data +public class FbpayIsvParams extends IsvParams { + + /** vendorSn 服务商ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String vendorSn; + + /** privateKey 服务商私钥 */ + private String privateKey; + + @Override + public String deSenData() { + + FbpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvsubMchParams.java new file mode 100644 index 0000000..6a3446a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayIsvsubMchParams.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.params.fbpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 付呗 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/5/13 10:31 + */ +@Data +public class FbpayIsvsubMchParams extends IsvsubMchParams { + + /** 服务商子商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subMchNo; + + /** 服务商子商户 门店号 **/ + private String storeNo; + + /** 服务商子商户 公众号appId **/ + private String wxSubAppId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayNormalMchParams.java new file mode 100644 index 0000000..7a22826 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fbpay/FbpayNormalMchParams.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.core.model.params.fbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 付呗 普通商户参数定义 + * + * @author xiaoyu + * + * @date 2022/5/13 11:23 + */ +@Data +public class FbpayNormalMchParams extends NormalMchParams { + + /** 商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchNo; + + /** 门店号 **/ + private String storeNo; + + /** privateKey */ + private String privateKey; + + + @Override + public String deSenData() { + + FbpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + mchParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/flpay/FlpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/flpay/FlpayIsvParams.java new file mode 100644 index 0000000..6758f04 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/flpay/FlpayIsvParams.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.params.flpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 福禄 配置信息 + */ +@Data +public class FlpayIsvParams extends IsvParams { + + /** 是否沙箱环境 1-是 */ + private String appId; + + /** 密钥 **/ + private String secret; + + private String taskNo; + + @Override + public String deSenData() { + FlpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.secret)) { + isvParams.setSecret(StringKit.autoDesensitization(this.secret)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayConfig.java new file mode 100644 index 0000000..0fddc1f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayConfig.java @@ -0,0 +1,137 @@ +package com.jeequan.jeepay.core.model.params.fuioupay; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Created by Ricky on 2016/11/19. + */ +public class FuioupayConfig { + + public static String BASE_URL_PAY = "https://spay-cloud.fuioupay.com"; // 支付正式域名 + // public static String BASE_URL_PAY = "https://spay-xs.fuioupay.com"; // 支付正式域名(旧) + public static String BASE_URL_PAY2 = "https://spay-mc.fuioupay.com"; // 支付正式域名2 + public static String BASE_URL_PAY_TEST = "https://fundwx.fuiou.com"; // 支付测试域名 + + public static String BASE_URL_APPLY = "https://mchntapi.fuioupay.com"; // 进件正式域名 + public static String BASE_URL_APPLY_TEST = "http://www-1.fuiou.com:28090/wmp"; // 进件测试域名 + + public static String BASE_URL_SHARE = "https://ordupz.fuioupay.com"; // 分账正式域名 + public static String BASE_URL_SHARE_TEST = "https://ordupz-test.fuioupay.com"; // 分账测试域名 + + public static String charset = "GBK"; // 编码 + + public static String version = "1.0"; // 版本号 + + public static String currType = "CNY"; // 币种 + + public static String PAY_SUCCESS = "SUCCESS"; // 成功 + public static String PAY_PAYERROR = "PAYERROR"; // 失败 + public static String PAY_USERPAYING = "USERPAYING"; // 支付中 + public static String PAY_NOTPAY = "NOTPAY"; // 未支付 + public static String PAY_CLOSED = "CLOSED"; // 已关闭 + public static String PAY_REVOKED = "REVOKED"; // 已撤销 + public static String PAY_REFUND = "REFUND"; // 已退款 + + public static String REFUND_SUCCESS = "SUCCESS"; // 退款成功 + public static String REFUND_PAYERROR = "PAYERROR"; // 退款失败 + + // 订单类型 + public static String ORDER_TYPE_ALIPAY = "ALIPAY"; + public static String ORDER_TYPE_WECHAT = "WECHAT"; + public static String ORDER_TYPE_UNIONPAY = "UNIONPAY"; + public static String ORDER_TYPE_BESTPAY = "BESTPAY"; + public static String ORDER_TYPE_DIGICCY = "DIGICCY"; + + public static String TRADE_TYPE_JSAPI = "JSAPI"; // 公众号支付 + public static String TRADE_TYPE_FWC = "FWC"; // 支付宝服务窗、支付宝小程序 + public static String TRADE_TYPE_LETPAY = "LETPAY"; // 微信小程序 + public static String TRADE_TYPE_BESTPAY = "BESTPAY"; // 翼支付js + public static String TRADE_TYPE_MPAY = "MPAY"; // 云闪付小程序(控件支付) + public static String TRADE_TYPE_UNIONPAY = "UNIONPAY"; // 云闪付扫码 + public static String TRADE_TYPE_UPBXJS = "UPBXJS"; // 云闪付保险缴费 + + + public static String FUIOU_MICROPAY = "/micropay"; //扫码 + public static String FUIOU_WXPRECREAT = "/wxPreCreate"; //公众号/服务窗统一下单 + public static String FUIOU_QUERY = "/commonQuery"; //查单 + public static String FUIOU_REFUND = "/commonRefund"; //退款 + public static String FUIOU_REFUND_QUERY = "/refundQuery"; //退款查询 + public static String FUIOU_REFUND_CLOSE_ORDER ="/closeorder"; //关闭订单 + public static String FUIOU_AUTH2OPENID ="/auth2Openid"; // 银联授权码获取user_id + + + public static String SUCCESS_CODE = "000000"; // 支付成功应答码 + public static String SUCCESS_CODE_APPLY = "0000"; // 进件成功应答码 + + public static byte POS_PAY_SUCCESS_CODE = 1; // 支付成功应答码 + public static byte POS_REFUND_SUCCESS_CODE = 2; // 退款成功应答码 + + // 条码、退款待查单应答码 + public static List needQueryOrderResultCodeList = new LinkedList<>(); + static { + needQueryOrderResultCodeList.add("030010"); + needQueryOrderResultCodeList.add("010002"); + needQueryOrderResultCodeList.add("9999"); + needQueryOrderResultCodeList.add("010001"); + needQueryOrderResultCodeList.add("2001"); + needQueryOrderResultCodeList.add("2002"); + } + + public static String getPayBaseUrl(Byte sandBox) { + return sandBox == null || sandBox == 0 ? BASE_URL_PAY : BASE_URL_PAY_TEST; + } + public static String getApplyBaseUrl(Byte sandBox) { + return sandBox == null || sandBox == 0 ? BASE_URL_APPLY : BASE_URL_APPLY_TEST; + } + public static String getShareBaseUrl(Byte sandBox) { + return sandBox == null || sandBox == 0 ? BASE_URL_SHARE : BASE_URL_SHARE_TEST; + } + + public static Map SETTLE_TP_CODE_MAP = new HashMap<>(); + + static { + SETTLE_TP_CODE_MAP.put("0.20", "M0110"); + SETTLE_TP_CODE_MAP.put("0.21", "M0139"); + SETTLE_TP_CODE_MAP.put("0.22", "Z0413"); + SETTLE_TP_CODE_MAP.put("0.23", "Z0323"); + SETTLE_TP_CODE_MAP.put("0.24", "M0083"); + SETTLE_TP_CODE_MAP.put("0.25", "M0196"); + SETTLE_TP_CODE_MAP.put("0.26", "M0175"); + SETTLE_TP_CODE_MAP.put("0.27", "M0174"); + SETTLE_TP_CODE_MAP.put("0.28", "Z0194"); + SETTLE_TP_CODE_MAP.put("0.29", "Z0584"); + SETTLE_TP_CODE_MAP.put("0.30", "M0215"); + SETTLE_TP_CODE_MAP.put("0.31", "M2002"); + SETTLE_TP_CODE_MAP.put("0.32", "M2003"); + SETTLE_TP_CODE_MAP.put("0.33", "M0261"); + SETTLE_TP_CODE_MAP.put("0.34", "M2004"); + SETTLE_TP_CODE_MAP.put("0.35", "M0136"); + SETTLE_TP_CODE_MAP.put("0.36", "M0340"); + SETTLE_TP_CODE_MAP.put("0.37", "M2005"); + SETTLE_TP_CODE_MAP.put("0.38", "M0325"); + SETTLE_TP_CODE_MAP.put("0.39", "M2006"); + SETTLE_TP_CODE_MAP.put("0.40", "M0022"); + SETTLE_TP_CODE_MAP.put("0.41", "M2007"); + SETTLE_TP_CODE_MAP.put("0.42", "M0493"); + SETTLE_TP_CODE_MAP.put("0.43", "M0408"); + SETTLE_TP_CODE_MAP.put("0.44", "Z0394"); + SETTLE_TP_CODE_MAP.put("0.45", "M0068"); + SETTLE_TP_CODE_MAP.put("0.46", "M0355"); + SETTLE_TP_CODE_MAP.put("0.47", "M0074"); + SETTLE_TP_CODE_MAP.put("0.48", "M0072"); + SETTLE_TP_CODE_MAP.put("0.49", "M0356"); + SETTLE_TP_CODE_MAP.put("0.50", "M0049"); + SETTLE_TP_CODE_MAP.put("0.51", "M1084"); + SETTLE_TP_CODE_MAP.put("0.52", "M0079"); + SETTLE_TP_CODE_MAP.put("0.53", "M2009"); + SETTLE_TP_CODE_MAP.put("0.54", "Z0392"); + SETTLE_TP_CODE_MAP.put("0.55", "M0069"); + SETTLE_TP_CODE_MAP.put("0.56", "M1082"); + SETTLE_TP_CODE_MAP.put("0.57", "M1074"); + SETTLE_TP_CODE_MAP.put("0.58", "Z0193"); + SETTLE_TP_CODE_MAP.put("0.59", "Z0203"); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvParams.java new file mode 100644 index 0000000..a573224 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvParams.java @@ -0,0 +1,105 @@ +package com.jeequan.jeepay.core.model.params.fuioupay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 富友 配置信息 + * + * @author zx + * + * @date 2022/3/8 18:02 + */ +@Data +public class FuioupayIsvParams extends IsvParams { + + /** 是否沙箱环境 1-是 */ + private Byte sandbox; + + /** 机构号,接入机构在富友的唯一代码 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String insCd; + + /** 机构编码(富友提供,4位),用于订单前缀 **/ + private String insCd4OrderPrefix; + + /** 终端号(没有真实终端号统一填88888888) **/ + private String termId; + + /** privateKey 私钥 **/ + private String privateKey; + + /** publicKey 富友公钥 **/ + private String publicKey; + + /** md5Key 进件密钥 **/ + private String md5Key; + + /** 进件ftp 帐号 **/ + private String applyFtpUser; + + /** 进件ftp 密码 **/ + private String applyFtpPwd; + + /** 分账ftp 帐号 **/ + private String shareFtpUser; + + /** 分账ftp 密码 **/ + private String shareFtpPwd; + + /** 公众号appid **/ + private String wxAppid; + + /** 小程序appid **/ + private String wxLiteAppid; + + /** 【云秘POS】ymSysId **/ + private String ymSysId; + + /** 【云秘POS】ymPosMd5Key 密钥 **/ + private String ymPosMd5Key; + + /** ymPosPrivateKey 【云秘POS】私钥 **/ + private String ymPosPrivateKey; + + /** ymPosPublicKey 【云秘POS】富友公钥 **/ + private String ymPosPublicKey; + + @Override + public String deSenData() { + + FuioupayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + if (StringUtils.isNotBlank(this.md5Key)) { + isvParams.setMd5Key(StringKit.autoDesensitization(this.md5Key)); + } + if (StringUtils.isNotBlank(this.applyFtpPwd)) { + isvParams.setApplyFtpPwd(StringKit.autoDesensitization(this.applyFtpPwd)); + } + if (StringUtils.isNotBlank(this.shareFtpPwd)) { + isvParams.setShareFtpPwd(StringKit.autoDesensitization(this.shareFtpPwd)); + } + if (StringUtils.isNotBlank(this.ymPosPrivateKey)) { + isvParams.setYmPosPrivateKey(StringKit.autoDesensitization(this.ymPosPrivateKey)); + } + if (StringUtils.isNotBlank(this.ymPosPublicKey)) { + isvParams.setYmPosPublicKey(StringKit.autoDesensitization(this.ymPosPublicKey)); + } + if (StringUtils.isNotBlank(this.ymPosMd5Key)) { + isvParams.setYmPosMd5Key(StringKit.autoDesensitization(this.ymPosMd5Key)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvsubMchParams.java new file mode 100644 index 0000000..7810520 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/fuioupay/FuioupayIsvsubMchParams.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.params.fuioupay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 富友 配置信息 + * + * @author zx + * + * @date 2022/3/8 18:02 + */ +@Data +public class FuioupayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号, 富友分配给二级商户的商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchntCd; + + /** 商户公众号appid **/ + private String wxSubAppid; + + /** 商户小程序appid **/ + private String wxSubLiteAppid; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvParams.java new file mode 100644 index 0000000..4266d0c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvParams.java @@ -0,0 +1,59 @@ +package com.jeequan.jeepay.core.model.params.hkpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 海科融通 服务商参数定义 + * + * @author yr + * + * @date 2022/11/30 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class HkpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** D0提现费率,最小值为0.02%(只填数值) */ + private String withdrawalRate; + + /** D0单笔提现最低手续费,最小值为0.2元(只填数值) */ + private String withdrawalFeeMin; + + /** 服务商编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String agentNo; + + /** 接入机构标识 */ + private String accessId; + + /** 服务商的接入秘钥,API接口签名使用 */ + private String accessKey; + + /** 微信渠道号 服务商通过海科在(微信)申请的渠道编号 */ + private String channelNoWx; + + /** 支付宝渠道号 服务商自行申请的支付宝渠道号 */ + private String channelNoAli; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + + @Override + public String deSenData() { + HkpayIsvParams isvParams = this; + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvsubMchParams.java new file mode 100644 index 0000000..641742b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hkpay/HkpayIsvsubMchParams.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.params.hkpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 海科融通 特约商户参数定义 + * + * @author yr + * + * @date 2022/11/30 + */ +@Data +public class HkpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchNo; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + public String deSenData() { + HkpayIsvsubMchParams hkpayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(hkpayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayConfig.java new file mode 100644 index 0000000..b187efc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayConfig.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.params.hmpay; + +import lombok.Data; + +/** + * 杉德[河马] 通用配置信息 + * + * @author xiaoyu + * + * @date 2021/12/22 17:20 + */ +@Data +public class HmpayConfig { + + /** 成功 **/ + public static String SUCCESS = "SUCCESS"; + /** 失败 **/ + public static String FAILED = "FAILED"; + /** 等待支付 **/ + public static String WAITING_PAYMENT = "WAITING_PAYMENT"; + /** 关闭失败 **/ + public static String CLOSE_FAILED = "CLOSE_FAILED"; + /** 关闭成功 **/ + public static String CLOSE_SUCCESS = "CLOSE_SUCCESS"; + /** 退款成功 **/ + public static String REFUND_SUCCESS = "REFUND_SUCCESS"; + /** 退款失败 **/ + public static String REFUND_FAILED = "REFUND_FAILED"; + + + /** 测试环境、正式环境交易请求地址 **/ + public static String SANDBOX_HM_PAY_HOST = "http://star.sandgate.cn/gateway/api"; + public static String PROD_HM_PAY_HOST = "https://hmpay.sandpay.com.cn/gateway/api"; + + /** 测试环境、正式环境商户报备请求地址 **/ + public static String SANDBOX_HM_APPLY_HOST = "https://star.sandgate.cn/agent-api/api"; + public static String PROD_HM_APPLY_HOST = "https://hmpay.sandpay.com.cn/agent-api/api"; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvParams.java new file mode 100644 index 0000000..24d7d71 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.params.hmpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 杉德[河马] 服务商配置 + * + * @author xiaoyu + * + * @date 2022/3/8 14:45 + */ +@Data +public class HmpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 服务商ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String appId; + + /** 支付产品编号 */ + private String productCode; + + /** 服务商私钥 */ + private String privateKey; + + /** 平台公钥 */ + private String publicKey; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + @Override + public String deSenData() { + + HmpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.str2Star(this.privateKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.str2Star(this.publicKey, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvsubMchParams.java new file mode 100644 index 0000000..9bde35d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayIsvsubMchParams.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.model.params.hmpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 杉德[河马] 服务商子商户配置 + * + * @author xiaoyu + * + * @date 2022/3/8 15:08 + */ +@Data +public class HmpayIsvsubMchParams extends IsvsubMchParams { + + /** 子商户ID **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subAppId; + + /** 小程序appId **/ + private String wxLiteAppId; + + /** 门店配置 **/ + private String mchStoreConfig; + + public JSONObject getJsonParams() { + JSONObject params = new JSONObject(); + params.put("subAppId", this.subAppId); + params.put("wxLiteAppId", this.wxLiteAppId); + if (StringUtils.isEmpty(this.mchStoreConfig)) { + params.put("mchStoreConfig", "[]"); + }else { + params.put("mchStoreConfig", this.mchStoreConfig); + } + return params; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayMchChildrenAccountParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayMchChildrenAccountParams.java new file mode 100644 index 0000000..426349b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hmpay/HmpayMchChildrenAccountParams.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.core.model.params.hmpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo; +import lombok.Data; + +/** + * 杉德[河马] 商户分账接收方参数 + * + * @author xiaoyu + * + * @date 2022/3/11 13:40 + */ +@Data +public class HmpayMchChildrenAccountParams extends ApplymentBasicInfo { + + /** 普通商户 **/ + public static String GENERAL_MERCHANT = "GENERAL_MERCHANT"; + /** 个人 **/ + public static String PERSONAL_MERCHANT = "PERSONAL_MERCHANT"; + /** 法人证件类型 **/ + public static String ACCOUNT_TYPE_IDCARD = "IDCard"; + + /** 河马付商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantNo; + + /** 商户流水号[与t_channel_account_info字段保持一直] **/ + private String channelReqNo; + + /** 账户名称 **/ + private String infoName; + + /** 账户类型 普通商户:GENERAL_MERCHANT 个人:PERSONAL_MERCHANT**/ + private String infoType; + + /** 营业执照名称 **/ + private String mchFullName; + + /** 工商网截图 **/ + private String businessNetworkPhoto; + + /** 公司性质 股份公司:STOCK_COMPANY 有限公司:LIMITED_COMPANY 个体工商户:INDIVIDUAL_BUSINESS 公共事业单位:GOVERNMENT_INSTITUTION 其他:OTHER**/ + private String accountCompanyType; + + /** 账户关系类型 服务商:SERVICE_PROVIDER 门店:STORE 合作伙伴:PARTNER 总部:HEAD_QUARTERS 品牌方:BRAND_PARTY 分销商:DISTRIBUTOR 供应商:SUPPLIER 其他:OTHER **/ + private String accountRelation; + + /** 法人证件类型 身份证:IDCard **/ + private String accountType; + + /** 联行行号 **/ + private String bankNameParamId; + + /** 银行预留手机号 **/ + protected String bankContactPhone; + + /** 分账计费模式 **/ + protected String feeType; + + + @Override + public String bankBranchNo() { + return bankNameParamId; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvParams.java new file mode 100644 index 0000000..e767ba0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvParams.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.hnapay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商参数定义 + * + * @author xiaoyu + * + * @date 2022/12/6 11:10 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class HnapayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 服务商编号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String orgNo; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 公众号appid **/ + private String wxAppid; + + /** 小程序appid **/ + private String wxLiteAppid; + + /** 应用私钥 **/ + private String privateKey; + + /** 新生公钥 **/ + private String publicKey; + + @Override + public String deSenData() { + HnapayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvsubMchParams.java new file mode 100644 index 0000000..2dc7501 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/hnapay/HnapayIsvsubMchParams.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.params.hnapay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/12/8 9:26 + */ +@Data +public class HnapayIsvsubMchParams extends IsvsubMchParams { + + /** 商户编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantNo; + + + public String deSenData() { + HnapayIsvsubMchParams isvsubMchParams = this; + return ((JSONObject) JSON.toJSON(isvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvParams.java new file mode 100644 index 0000000..58af0af --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvParams.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.params.icbcpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商配置参数 + * + * @author xiaoyu + * + * @date 2023/1/3 16:18 + */ +@Data +public class IcbcpayIsvParams extends IsvParams { + + /** 环境配置 1-沙箱环境 0-生产环境 **/ + private Byte sandbox; + + /** APP_ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String appId; + + /** 收单产品协议编号 */ + private String merPrtclNo; + + /** 微信appId */ + private String wxAppId; + + /** 应用私钥 **/ + private String privateKey; + + /** 工行公钥 **/ + private String publicKey; + + @Override + public String deSenData() { + + IcbcpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvsubMchParams.java new file mode 100644 index 0000000..87b483b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/icbcpay/IcbcpayIsvsubMchParams.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.icbcpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2023/1/3 16:21 + */ +@Data +public class IcbcpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 merId**/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayConfig.java new file mode 100644 index 0000000..d5be0ad --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayConfig.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.params.joinpay; + +import lombok.Data; + +/* + * 汇聚支付 通用配置信息 + * + * @author yurong + * + * @date 2022/7/18 9:49 + */ +@Data +public class JoinpayConfig { + //加密类型 + public static final String ENCRYPT_TYPE_MD5 = "1"; // MD5加密 + public static final String ENCRYPT_TYPE_RSA = "2"; // RSA加密 + + //请求相关 + public static final String REQ_URL = "https://www.joinpay.com"; // 请求地址 + public static final String UNI_PAY_API = "/trade/uniPayApi.action"; // 下单 + public static final String QUERY_ORDER = "/trade/queryOrder.action"; // 订单查询 + public static final String REFUND = "/trade/refund.action"; // 退款 + public static final String QUERY_REFUND = "/trade/queryRefund.action"; // 退款查询 + + //支付类型 + public static final String WEIXIN_NATIVE = "WEIXIN_NATIVE"; // 微信扫码 + public static final String WEIXIN_CARD = "WEIXIN_CARD"; // 微信条码 + public static final String WEIXIN_APP3 = "WEIXIN_APP3"; // 微信 APP+支付 + public static final String WEIXIN_H5_PLUS = "WEIXIN_H5_PLUS"; // 微信 H5 支付 + public static final String WEIXIN_GZH = "WEIXIN_GZH"; // 微信公众号 + public static final String WEIXIN_XCX = "WEIXIN_XCX"; // 微信小程序支付 + + public static final String ALIPAY_NATIVE = "ALIPAY_NATIVE"; // 支付宝扫码(主扫) + public static final String ALIPAY_CARD = "ALIPAY_CARD"; // 支付宝条码 + public static final String ALIPAY_H5 = "ALIPAY_H5"; // 支付宝 H5 + public static final String ALIPAY_FWC = "ALIPAY_FWC"; // 支付宝服务窗 + public static final String ALIPAY_SYT = "ALIPAY_SYT"; // 支付宝收银台 + + //状态 + public static final String STATE_SUCCESS = "100"; // 成功 + public static final String STATE_FAIL = "101"; // 失败 + public static final String STATE_WAITING = "102"; // 订单处理中 + + //其他常量 + public static final String VERSION = "2.1"; // 汇聚版本号 + public static final String CNY = "1"; // 货币种类 1:人民币 + public static final String KEY_ALGORITHM = "RSA"; // 加密算法RSA + public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; // 签名算法 +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayNormalMchParams.java new file mode 100644 index 0000000..cb5e839 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/joinpay/JoinpayNormalMchParams.java @@ -0,0 +1,75 @@ +package com.jeequan.jeepay.core.model.params.joinpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 汇聚支付 配置信息 + * + * @author yurong + * + * @date 2022/7/18 9:49 + */ +@Data +public class JoinpayNormalMchParams extends NormalMchParams { + + /** + * 商户号 + **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantNo; + + /** + * 报备商户号 + **/ + private String tradeMerchantNo; + + /** + * 终端设备号 被扫必填 商家扫客户 + **/ + private String terminalNo; + + /** + * 加密类型 MD5 1 和 RSA 2 + **/ + private String encryptType; + + /** + * 秘钥 MD5加签 + **/ + private String merchantKey; + + /** + * 商户私钥 RSA加签 + **/ + private String privateKey; + + /** + * 汇聚平台公钥 RSA解签 + **/ + private String publicKey; + + + @Override + public String deSenData() { + + JoinpayNormalMchParams joinParams = this; + if (StringUtils.isNotBlank(this.merchantKey)) { + joinParams.setMerchantKey(StringKit.str2Star(this.merchantKey, 0, 3, 6)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + joinParams.setPublicKey(StringKit.str2Star(this.publicKey, 0, 3, 6)); + } + if (StringUtils.isNotBlank(this.privateKey)) { + joinParams.setPrivateKey(StringKit.str2Star(this.privateKey, 0, 3, 6)); + } + return ((JSONObject) JSON.toJSON(joinParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvParams.java new file mode 100644 index 0000000..80dbd09 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvParams.java @@ -0,0 +1,67 @@ +package com.jeequan.jeepay.core.model.params.kdbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 开店宝 服务商参数定义 + * + * @author yr + * + * @date 2023/03/27 + */ +@Data +public class KdbpayIsvParams extends IsvParams { + + /** 渠道商编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String agentNo; + + /** 渠道密钥 */ + private String agentKey; + + /** 业务员编号 */ + private String empNo; + + /** 清算周期 00-T+1 01-D0 02-D+1 (00是清算周期,T1是结算周期) T1组合渠道侧暂不支持20231031 **/ + private String settType; + + /** 微信渠道号 */ + private String wxChannelId; + /** 微信渠道名称 */ + private String wxChannelName; + + /** 支付宝伙伴id */ + private String aliPartnerId; + /** 支付宝伙伴名称 **/ + public String aliPartnerName; + + + /** 微信开户意愿地址 */ + private String wxUrl; + /** 支付宝商家认证地址 */ + private String aliUrl; + + + @Override + public String deSenData() { + KdbpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.agentKey)) { + isvParams.setAgentKey(StringKit.str2Star(this.agentKey, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.wxChannelId)) { + isvParams.setWxChannelId(StringKit.str2Star(this.wxChannelId, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.aliPartnerId)) { + isvParams.setAliPartnerId(StringKit.str2Star(this.aliPartnerId, 4, 4, 6)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvsubMchParams.java new file mode 100644 index 0000000..a6eab3c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kdbpay/KdbpayIsvsubMchParams.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.params.kdbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 开店宝 特约商户参数定义 + * + * @author yr + * + * @date 2023/3/27 9:06 + */ +@Data +public class KdbpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String orgMerCode; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + public String deSenData() { + KdbpayIsvsubMchParams kdbpayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(kdbpayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayConfig.java new file mode 100644 index 0000000..d4aa873 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayConfig.java @@ -0,0 +1,4 @@ +package com.jeequan.jeepay.core.model.params.kqpay; + +public class KqpayConfig { +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvParams.java new file mode 100644 index 0000000..38d9983 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvParams.java @@ -0,0 +1,70 @@ +package com.jeequan.jeepay.core.model.params.kqpay; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class KqpayIsvParams extends IsvParams { + + /** 加密方式 RSA/SM */ + private String signType; + + /** 商户支付模式 1-支付 2-分账 */ + private Byte payType; + + /** 支付宝渠道拓展二维码URL */ + private String aliChannelExtUrl; + + /** 微信渠道拓展二维码URL */ + private String wxOpenUrl; + + /** 快钱平台账号 */ + private String vendorMemberCode; + + + /** 私钥证书(.pfx/.sm2) */ + private String merchantDefaultPrivatePath; + + private String merchantDefaultPrivatePassword; + + private String bill99DefaultPublicPath; + + /** + * 备选选参数,暂不考虑 + */ + private String merchantAlternatePrivatePath; + + private String merchantAlternatePrivatePassword; + + private String bill99AlternatePublicPath; + + /** + * ssl证书文件地址 + */ + private String sslPublicPath; + + private String sslProtocol; + + private String storeType; + + private String storePwd; + + private String alias; + + private String priority; + + private String personalInfomationAttorney; + + /** + * 是否需要签约, + */ + private String needSignFlag; + + @Override + public String deSenData() { + return JSON.toJSONString(this); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvsubMchParams.java new file mode 100644 index 0000000..bd52ae5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/KqpayIsvsubMchParams.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.params.kqpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +import java.util.List; + +@Data +public class KqpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subMerchantId; + + private String subMemberCode; + + /** 终端号**/ + private List terminalInfos; + + public String deSenData() { + KqpayIsvsubMchParams mchParams = this; + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/README.md b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/README.md new file mode 100644 index 0000000..fcd0fc4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/kqpay/README.md @@ -0,0 +1 @@ +# 快钱支付 diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayConfig.java new file mode 100644 index 0000000..30ebc10 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayConfig.java @@ -0,0 +1,101 @@ +/** + * cljpay.com + * Copyright (C) 2015-2022 All Rights Reserved. + */package com.jeequan.jeepay.core.model.params.leshuapay; + +import lombok.Data; + +/** + * @author yangjun + * @version LeshuapayConfig.java, v 0.1 2022-10-26 17:28 yangjun + */ +@Data +public class LeshuapayConfig { + + /** 交易网关地址 */ + public static String PAY_SANDBOX_URL = "https://t-paygate.lepass.cn/cgi-bin/lepos_pay_gateway.cgi"; // 测试 + public static String PAY_URL = "https://paygate.leshuazf.com/cgi-bin/lepos_pay_gateway.cgi"; // 正式 + /** 商户网关地址(进件) */ + public static String MCH_SANDBOX_URL = "http://t-saas-mch.lepass.cn/apiv2"; + public static String MCH_URL = "https://saas-mch.leshuazf.com/apiv2"; + + /** + * 成功状态码 + */ + public static final String PAY_SUCCESS_CODE = "0"; + /** + * 成功状态码 + */ + public static final String SHARE_SUCCESS_CODE = "000000"; + public static final String SHARE_AUDITING_CODE = "000011"; + public static final String SHARE_AUTOMATIC_AUDITING_CODE = "000022"; + public static final String SHARE_ERROR_CODE = "000019"; + + /** + * 超时时间 + */ + public static final Integer LESHUA_MERCHANT_GATEWAY_TIMEOUT = 10000; + + + /** + * 0-支付宝Native扫码支付、银联Native扫码支付、数字货币支付 + */ + public static final String QR_JSPAY_FLAG = "0"; + + /** + * 1-微信JSAPI、支付宝JSAPI支付、银联JSAPI支付 + */ + public static final String JS_JSPAY_FLAG = "1"; + + /** + * 2-微信、支付宝简易支付<跳转乐刷收银台支付>;(jspay_flag=2时必传jump_url,否则会报错) + */ + public static final String EASY_JSPAY_FLAG = "2"; + + /** + * 3-微信小程序支付、支付宝小程序支付 + */ + public static final String LITE_JSPAY_FLAG = "3"; + + + /** + * 退款标识 + */ + public static final String TRADE_TYPE_REFUND_MARK = "leshua_refund_id"; + + /** + * alipayjsapi 支付宝订单号 + */ + public static final String TRADE_TYPE_ALIPAY_JSAPI_TRADE_NO_MARK = "tradeNO"; + + /** + * 微信支付订单回传门店编码 + */ + public static final String TRADE_WX_SCENE_INFO = "{\"store_info\":{\"id\":\"{}\"}}"; + + /** + * 商户进件相关请求地址 + */ + public static final String LESHUA_PIC_UPLOAD = "/picture/upload"; // 图片上传 + public static final String LESHUA_MCH_APPLY = "/merchant/register"; // 进件 + public static final String LESHUA_APPLY_RATE = "/merchant/open"; // 商户设置费率 + public static final String LESHUA_AUDIT_QUERY = "/merchant/audit_qry"; //商户审核查询 + public static final String LESHUA_WECHAT_WXPAYCONFIG = "/wechat/wxpayconfig"; //微信支付配置 + public static final String LESHUA_WECHAT_WXPAYCONFIG_QUERY = "/wechat/wxpayconfig_qry"; //查询微信支付配置 + public static final String LESHUA_WX_VERIFY_QUERY = "/submch/getauthorizestateByWxMerId"; //微信授权状态查询 + public static final String LESHUA_ALI_VERIFY_QUERY = "/zfbVerify/queryMchStatus"; //支付宝子商户授权状态查询 + public static final String LESHUA_APPLY_UPDATE = "/merchant/update"; //商户信息修改 + + + /*** + * 乐刷进件结果查询状态 + */ + + public static final String REJECTED = "REJECTED"; //退回 + public static final String REVIEW = "REVIEW"; //待人工检查 + public static final String PASSED = "PASSED"; //通过 + public static final String UNKNOWN = "UNKNOWN"; //未知 + public static final String ADD_INFO = "ADD_INFO"; //待完善资料 + public static final String AUDITING = "AUDITING"; //待审核 + +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvParams.java new file mode 100644 index 0000000..652d1ef --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvParams.java @@ -0,0 +1,69 @@ +/** + * cljpay.com + * Copyright (C) 2015-2022 All Rights Reserved. + */package com.jeequan.jeepay.core.model.params.leshuapay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * @author yangjun + * @version LeshuapayIsvParams.java, v 0.1 2022-10-26 17:28 yangjun + */ +@Data +public class LeshuapayIsvParams extends IsvParams { + + /** + * 是否沙箱环境 + */ + private Byte sandbox; + + /** + * 商户网关服务商ID(服务商编号) + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String merchantGatewayAgentId; + + /** + * 商户网关(进件)密钥 + */ + private String merchantGatewayPrivateKey; + + /** + * 交易密钥 + */ + private String payGatewayPrivateKey; + + /** + * 通知密钥 + */ + private String noticeGatewayPrivateKey; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + + @Override + public String deSenData() { + LeshuapayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.merchantGatewayPrivateKey)) { + isvParams.setMerchantGatewayPrivateKey(StringKit.autoDesensitization(this.merchantGatewayPrivateKey)); + } + if (StringUtils.isNotBlank(this.payGatewayPrivateKey)) { + isvParams.setPayGatewayPrivateKey(StringKit.autoDesensitization(this.payGatewayPrivateKey)); + } + if (StringUtils.isNotBlank(this.noticeGatewayPrivateKey)) { + isvParams.setNoticeGatewayPrivateKey(StringKit.autoDesensitization(this.noticeGatewayPrivateKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvsubMchParams.java new file mode 100644 index 0000000..73cd21b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/leshuapay/LeshuapayIsvsubMchParams.java @@ -0,0 +1,47 @@ +/** + * cljpay.com + * Copyright (C) 2015-2022 All Rights Reserved. + */package com.jeequan.jeepay.core.model.params.leshuapay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * @author yangjun + * @version LeshuapayIsvsubMchParams.java, v 0.1 2022-10-26 17:28 yangjun + */ +@Data +public class LeshuapayIsvsubMchParams extends IsvsubMchParams { + + /** + * 商户号 + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantId; + + /** + * 指定支付方式 + * 1:禁止使用信用卡; + * 0或者不填:不限制 + */ + private String limitPay; + + /** + * 默认为0 + * 0:d1交易 + * 1:d0交易 + */ + private String t0; + + /** + * 商户公众号appid + */ + private String wxSubAppid; + + /** + * 商户小程序appid + */ + private String wxSubLiteAppid; +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvParams.java new file mode 100644 index 0000000..f5920ae --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvParams.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.core.model.params.lklpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +/** + * 拉卡拉 isv参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:08 + */ +@Data +public class LklpayIsvParams extends IsvParams { + + private String settType; + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** appId */ + private String appId; + + /** 证书序列号 */ + private String serialNo; + + /** 汇拓客用户号 */ + private Long userNo; + + /** 汇拓客机构号 */ + private String clientId; + + /** 汇拓客机构秘钥 */ + private String clientSecret; + + /** 机构代码 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String orgCode; + + /** 微信渠道号 */ + private String wxChannelId; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 私钥证书 */ + private String privateCert; + + /** 公钥证书 */ + private String publicCert; + + private Integer activityId; + + @Override + public String deSenData() { + LklpayIsvParams isvParams = this; +// if (StringUtils.isNotBlank(this.appId)) { +// isvParams.setAppId(StringKit.autoDesensitization(this.appId)); +// } +// if (StringUtils.isNotBlank(this.serialNo)) { +// isvParams.setSerialNo(StringKit.autoDesensitization(this.serialNo)); +// } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvsubMchParams.java new file mode 100644 index 0000000..5b44750 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklpay/LklpayIsvsubMchParams.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.params.lklpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 拉卡拉 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:23 + */ +@Data +public class LklpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merCupNo; + + /** 终端号 */ + private String termNo; + + /** 微信子商户号 */ + private String subMchId; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvParams.java new file mode 100644 index 0000000..f54443f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvParams.java @@ -0,0 +1,94 @@ +package com.jeequan.jeepay.core.model.params.lklsb2bpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 拉卡拉 isv参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:08 + */ +@Data +public class Lklsb2bpayIsvParams extends IsvParams { + + /** + * 拉卡拉平台公钥, 这里暂时写死 + */ + public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXCrnI36j2nBpZhbHvgrMZdsGOYSWigvuVaDm/FEHPcQJJsYrs/eK3Vs7XtFSezaIf95r+YD0fewLOgw31FuZOcraf5P0I/BGuvpWfstwuI28UfzNld+XzXy0YHsmo010VgwkGJrKFezQHjKD85HT57iBoEQiUt+00+X0D/rJ2MQIDAQAB"; + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** appId */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String appId; + + /** 合作方编号 */ + private String userNo; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 用户名 */ + private String clientId; + + /** 密码 */ + private String clientSecret; + + /** APP用户名 */ + private String appUserName; + + /** APP密码 */ + private String appPassword; + + /** 归属活动信息 拓客SAAS分配 */ + private String activityId; + + /** RSA私钥 */ + private String rsaPrivateKey; + + /** RSA公钥 */ + private String rsaPublicKey; + + /** 证书序列号 */ + private String serialNo; + + /** 私钥证书 */ + private String privateCert; + + /** 公钥证书 */ + private String publicCert; + + /** 机构号 */ + private String orgCode; + + private String settType; + + /** + * 微信渠道号 + */ + private String wxChannelId; + + @Override + public String deSenData() { + Lklsb2bpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.rsaPrivateKey)) { + isvParams.setRsaPrivateKey(StringKit.autoDesensitization(this.rsaPrivateKey)); + } + if (StringUtils.isNotBlank(this.rsaPublicKey)) { + isvParams.setRsaPublicKey(StringKit.autoDesensitization(this.rsaPublicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvsubMchParams.java new file mode 100644 index 0000000..a4e1122 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklsb2bpay/Lklsb2bpayIsvsubMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.lklsb2bpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 拉卡拉 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:23 + */ +@Data +public class Lklsb2bpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String externalCustomerNo; + + /** 终端号 */ + private String termNo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvParams.java new file mode 100644 index 0000000..357396b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvParams.java @@ -0,0 +1,97 @@ +package com.jeequan.jeepay.core.model.params.lklspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 拉卡拉 isv参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:08 + */ +@Data +public class LklspayIsvParams extends IsvParams { + + /** + * 拉卡拉平台公钥, 这里暂时写死 + */ + public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHB7j7gG3ioLnnr7bsuEXTAh/8YSxSp4lQIYGW9gX0Ikgz9JqARdg4iEnU6tgNirxA6Jdg0AWgLJQxQBEZMkwyK2ZfYgesYhlJkv6WVC8v5OkOrhA9NSQ3iS6JsYegsZO0GJSTtLQaTOF8WobPYe5NI+eWU1fRz2ZyxlWlKshBeQIDAQAB"; + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** appId */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String appId; + + /** 合作方编号 */ + private String userNo; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 用户名 */ + private String clientId; + + /** 密码 */ + private String clientSecret; + + /** APP用户名 */ + private String appUserName; + + /** APP密码 */ + private String appPassword; + + /** 归属活动信息 拓客SAAS分配 */ + private String activityId; + + /** RSA私钥 */ + private String rsaPrivateKey; + + /** RSA公钥 */ + private String rsaPublicKey; + + /** 证书序列号 */ + private String serialNo; + + /** 私钥证书 */ + private String privateCert; + + /** 公钥证书 */ + private String publicCert; + + /** 机构号 */ + private String orgCode; + + private String settType; + + /** + * 微信渠道号 + */ + private String wxChannelId; + + @Override + public String deSenData() { + LklspayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.rsaPrivateKey)) { + isvParams.setRsaPrivateKey(StringKit.autoDesensitization(this.rsaPrivateKey)); + } + if (StringUtils.isNotBlank(this.rsaPublicKey)) { + isvParams.setRsaPublicKey(StringKit.autoDesensitization(this.rsaPublicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + public static void main(String[] args){ + System.out.println("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHB7j7gG3ioLnnr7bsuEXTAh/8YSxSp4lQIYGW9gX0Ikgz9JqARdg4iEnU6tgNirxA6Jdg0AWgLJQxQBEZMkwyK2ZfYgesYhlJkv6WVC8v5OkOrhA9NSQ3iS6JsYegsZO0GJSTtLQaTOF8WobPYe5NI+eWU1fRz2ZyxlWlKshBeQIDAQAB".equals(PUB_KEY)); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvsubMchParams.java new file mode 100644 index 0000000..93806dd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lklspay/LklspayIsvsubMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.lklspay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 拉卡拉 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:23 + */ +@Data +public class LklspayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String externalCustomerNo; + + /** 终端号 */ + private String termNo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lmspay/LmspayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lmspay/LmspayIsvParams.java new file mode 100644 index 0000000..bd489a4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/lmspay/LmspayIsvParams.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.params.lmspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 立码收 配置参数 +* +* @author zhuxiao +* +* @date 2021/6/8 18:02 +*/ +@Data +public class LmspayIsvParams extends IsvParams { + + /** 加密密钥 */ + private String secretKey; + + /** 商户公钥 */ + private String publicKey; + + + @Override + public String deSenData() { + + LmspayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.secretKey)) { + isvParams.setSecretKey(StringKit.autoDesensitization(this.secretKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + return ((JSONObject)JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvParams.java new file mode 100644 index 0000000..7888e40 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvParams.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.core.model.params.mbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 米花支付 isv参数定义 + * + * @author yr + * + * @date 2022/9/20 14:16 + */ +@Data +public class MbpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 私钥 */ + private String privateKey; + + /** 公钥 */ + private String mbPublicKey; + + @Override + public String deSenData() { + MbpayIsvParams mchParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + mchParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.mbPublicKey)) { + mchParams.setMbPublicKey(StringKit.autoDesensitization(this.mbPublicKey)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvsubMchParams.java new file mode 100644 index 0000000..7f42a50 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayIsvsubMchParams.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.params.mbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 米花支付 特约商户参数定义 + * + * @author yr + * + * @date 2022/9/20 14:16 + */ +@Data +public class MbpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户标识 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merAccount; + + /** 用户编号 */ + private String merNo; + + public String deSenData() { + MbpayIsvsubMchParams mchParams = this; + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayNormalMchParams.java new file mode 100644 index 0000000..66ce09c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/mbpay/MbpayNormalMchParams.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.params.mbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 米花支付 普通商户参数定义 + * + * @author yr + * + * @date 2022/9/16 11:16 + */ +@Data +public class MbpayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户标识 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merAccount; + + /** 用户编号 */ + private String merNo; + + /** 私钥 */ + private String privateKey; + + /** 公钥 */ + private String mbPublicKey; + + @Override + public String deSenData() { + MbpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + mchParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.mbPublicKey)) { + mchParams.setMbPublicKey(StringKit.autoDesensitization(this.mbPublicKey)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvParams.java new file mode 100644 index 0000000..21767cd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvParams.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.params.pfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +/** + * 浦发 isv参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:08 + */ +@Data +public class PfpayIsvParams extends IsvParams { + + @Override + public String deSenData() { + PfpayIsvParams isvParams = this; + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvsubMchParams.java new file mode 100644 index 0000000..787af20 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayIsvsubMchParams.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.core.model.params.pfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 浦发 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:23 + */ +@Data +public class PfpayIsvsubMchParams extends IsvsubMchParams { + + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchNo; + + /** 门店编号 */ + private String storeNo; + + /** 终端号 */ + private String terminalNo; + + /** 应用标识 */ + private String appClientId; + + /** 请求秘钥 */ + private String clientSecret; + + /** 商户RSA私钥 **/ + private String mchPrivateKey; + + /** 浦发公钥 */ + private String pfpayPublicKey; + + public String deSenData() { + PfpayIsvsubMchParams mchParams = this; + if (StringUtils.isNotBlank(this.mchPrivateKey)) { + mchParams.setMchPrivateKey(StringKit.autoDesensitization(this.mchPrivateKey)); + } + if (StringUtils.isNotBlank(this.pfpayPublicKey)) { + mchParams.setPfpayPublicKey(StringKit.autoDesensitization(this.pfpayPublicKey)); + } + if (StringUtils.isNotBlank(this.clientSecret)) { + mchParams.setClientSecret(StringKit.autoDesensitization(this.clientSecret)); + } + + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayNormalMchParams.java new file mode 100644 index 0000000..89d1e62 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pfpay/PfpayNormalMchParams.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.core.model.params.pfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 浦发银行 普通商户参数定义 + * + * @author xiaoyu + * + * @date 2022/5/9 14:16 + */ +@Data +public class PfpayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchNo; + + /** 门店编号 */ + private String storeNo; + + /** 终端号 */ + private String terminalNo; + + /** 应用标识 */ + private String appClientId; + + /** 请求秘钥 */ + private String clientSecret; + + /** 商户RSA私钥 **/ + private String mchPrivateKey; + + /** 浦发公钥 */ + private String pfpayPublicKey; + + @Override + public String deSenData() { + PfpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.mchPrivateKey)) { + mchParams.setMchPrivateKey(StringKit.autoDesensitization(this.mchPrivateKey)); + } + if (StringUtils.isNotBlank(this.pfpayPublicKey)) { + mchParams.setPfpayPublicKey(StringKit.autoDesensitization(this.pfpayPublicKey)); + } + if (StringUtils.isNotBlank(this.clientSecret)) { + mchParams.setClientSecret(StringKit.autoDesensitization(this.clientSecret)); + } + + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvParams.java new file mode 100644 index 0000000..967b5e5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvParams.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.params.pmpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * PayerMax支付 isv参数定义 + * + * @author zx + * + * @date 2022/9/20 14:16 + */ +@Data +public class PmpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 服务商号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String spMerchantNo; + + /** 服务商应用AppId */ + private String appId; + + /** 服务商私钥 */ + private String privateKey; + + /** PayerMax平台公钥 */ + private String publicKey; + + @Override + public String deSenData() { + PmpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvsubMchParams.java new file mode 100644 index 0000000..32de705 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayIsvsubMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.pmpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * PayerMax支付 特约商户参数定义 + * + * @author zx + * + * @date 2022/9/20 14:16 + */ +@Data +public class PmpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantNo; + + /** 授权authToken */ + private String authToken; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayNormalMchParams.java new file mode 100644 index 0000000..b7131fb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pmpay/PmpayNormalMchParams.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.params.pmpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * PayerMax支付 普通商户参数定义 + * + * @author zx + * + * @date 2022/9/16 11:16 + */ +@Data +public class PmpayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantNo; + + /** 商户应用AppId */ + private String appId; + + /** 商户私钥 */ + private String privateKey; + + /** PayerMax平台公钥 */ + private String publicKey; + + @Override + public String deSenData() { + PmpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + mchParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + mchParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pppay/PpPayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pppay/PpPayNormalMchParams.java new file mode 100644 index 0000000..ad7773b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/pppay/PpPayNormalMchParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.params.pppay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * none. + * + * @author 陈泉 + * @package com.jeequan.jeepay.core.model.params.pppay + * @create 2021/11/15 18:10 + */ +@Data +public class PpPayNormalMchParams extends NormalMchParams { + /** + * 是否沙箱环境 + */ + private Byte sandbox; + + /** + * clientId + * 客户端 ID + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String clientId; + + /** + * secret + * 密钥 + */ + private String secret; + + /** + * 支付 Webhook 通知 ID + */ + private String notifyWebhook; + + /** + * 退款 Webhook 通知 ID + */ + private String refundWebhook; + + @Override + public String deSenData() { + PpPayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.secret)) { + mchParams.setSecret(StringKit.str2Star(this.secret, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvParams.java new file mode 100644 index 0000000..91466b8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvParams.java @@ -0,0 +1,81 @@ +package com.jeequan.jeepay.core.model.params.ruipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 瑞银信 服务商参数定义 + * + * @author yr + * + * @date 2022/8/23 16:00 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class RyxpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户私钥文件(交易使用) ryxss_pkcs8_rsa_private_key */ + private String cooperatorPriKey; + + /** 瑞银信公钥文件(交易使用) ryxsmzf_rsa_public_key */ + private String smzfPubKey; + + /** 合作方标识Cooperator */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String cooperator; + + /** 接入方id(进件使用) */ + private String accessId; + + /** 机构Id(进件使用) */ + private String orgId; + + /** 服务商机构标识码 银联 */ + private String pnrInsIdCd; + + /** 服务端公钥(进件使用) */ + private String publicKey; + + /** 客户端私钥(进件使用) */ + private String privateKey; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + /** 支付授权目录 */ + private String jsapiPath; + + /** 子商户号 */ + private String subAppId; + + @Override + public String deSenData() { + RyxpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.cooperatorPriKey)) { + isvParams.setCooperatorPriKey(StringKit.autoDesensitization(this.cooperatorPriKey)); + } + if (StringUtils.isNotBlank(this.smzfPubKey)) { + isvParams.setSmzfPubKey(StringKit.autoDesensitization(this.smzfPubKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvsubMchParams.java new file mode 100644 index 0000000..5f2ec56 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ruipay/RyxpayIsvsubMchParams.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.params.ruipay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 瑞银信 特约商户参数定义 + * + * @author yr + * + * @date 2022/8/23 16:00 + */ +@Data +public class RyxpayIsvsubMchParams extends IsvsubMchParams { + + /** 瑞银信商编 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantCode; + + /** 商户内部编号 */ + private String merInId; + + /** 终端编号 */ + private String termId; + + public String deSenData() { + RyxpayIsvsubMchParams ruipayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(ruipayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayConfig.java new file mode 100644 index 0000000..3c676e5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayConfig.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.sandpay; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +/** + * 杉德 通用配置信息 + * + * @author xiaoyu + * + * @date 2021/12/22 17:20 + */ +@Data +public class SandpayConfig { + + public static String REQ_URL = "https://cashier.sandpay.com.cn/gateway/api"; + public static String ORDER_PAY = "/order/pay"; + public static String ORDER_QUERY = "/order/query"; + public static String ORDER_REFUND = "/order/refund"; + /** 成功状态 **/ + public static String SUCCESS = "000000"; + public static String WAITING = "030020"; + public static String NOTIFY_SUCCESS = "1"; + + //接口名称 + public static String ORDERPAY = "sandpay.trade.pay"; //统一下单 + public static String ORDERPAY_BARPAY = "sandpay.trade.barpay"; //条码下单 + public static String ORDERQUERY = "sandpay.trade.query"; //订单查询 + public static String ORDERREFUND = "sandpay.trade.refund"; //退货 + public static String CLEARFILEDOWNLOAD = "sandpay.trade.download"; //对账单下载 + + //产品编码 + /** 支付宝扫码 **/ + public static String PRODUCTID_ALIPAY_QR = "00000006"; + /** 支付宝生活号 **/ + public static String PRODUCTID_ALIPAY_JSAPI = "00002022"; + /** 支付宝小程序 **/ + public static String PRODUCTID_ALIPAY_LITE = "00002023"; + /** 支付宝app **/ + public static String PRODUCTID_ALIPAY_JSAPI_APP = "02020004"; + /** 微信小程序 **/ + public static String PRODUCTID_WXPAY_LITE = "02010006"; + /** 微信公众号 **/ + public static String PRODUCTID_WXPAY_JSAPI = "02010002"; + + + public static final Map WAY_CODE_MAP = new HashMap<>(); + static { + WAY_CODE_MAP.put("ALI_QR", PRODUCTID_ALIPAY_QR); + WAY_CODE_MAP.put("ALI_BAR", PRODUCTID_ALIPAY_QR); + WAY_CODE_MAP.put("ALI_JSAPI", PRODUCTID_ALIPAY_JSAPI); + WAY_CODE_MAP.put("ALI_APP", PRODUCTID_ALIPAY_JSAPI_APP); + WAY_CODE_MAP.put("WX_JSAPI", PRODUCTID_ALIPAY_JSAPI_APP); + WAY_CODE_MAP.put("WX_LITE", PRODUCTID_ALIPAY_JSAPI_APP); + WAY_CODE_MAP.put("SAND_H5", "02010006"); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayNormalMchParams.java new file mode 100644 index 0000000..48c2804 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sandpay/SandpayNormalMchParams.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.core.model.params.sandpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 杉德 普通商户参数定义 + * + * @author xiaoyu + * + * @date 2021/12/22 17:15 + */ +@Data +public class SandpayNormalMchParams extends NormalMchParams { + + /** 商户ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mid; + + /** 杉德公钥文件 */ + private String publicCert; + + /** 商户私钥文件 */ + private String privateCert; + + /** 商户私钥密码 **/ + private String privatePassword; + + /** MD5签名key **/ + private String md5Key; + + /** 商户密钥, 手机APK工具 生成的key1 **/ + private String key1; + + @Override + public String deSenData() { + SandpayNormalMchParams mchParams = this; + + if (StringUtils.isNotBlank(this.privatePassword)) { + mchParams.setPrivatePassword(StringKit.str2Star(this.privatePassword, 4, 4, 6)); + } + + if (StringUtils.isNotBlank(this.md5Key)) { + mchParams.setMd5Key(StringKit.str2Star(this.md5Key, 4, 6, 6)); + } + + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvParams.java new file mode 100644 index 0000000..2fd48e6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvParams.java @@ -0,0 +1,60 @@ +package com.jeequan.jeepay.core.model.params.sftpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 微信官方支付 配置参数 +* +* @author zhuxiao +* +* @date 2021/6/8 18:02 +*/ +@Data +public class SftpayIsvParams extends IsvParams { + + /** 应用App ID */ + private String appId; + + /** 微信支付商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String mchId; + + /** oauth2地址 */ + private String oauth2Url; + + /** API V3秘钥 **/ + private String apiV3Key; + + /** 序列号 **/ + private String serialNo; + + /** API证书(.p12格式)**/ + private String cert; + + /** 证书文件(.pem格式) **/ + private String apiClientCert; + + /** 私钥文件(.pem格式) **/ + private String apiClientKey; + + + @Override + public String deSenData() { + + SftpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.apiV3Key)) { + isvParams.setApiV3Key(StringKit.str2Star(this.apiV3Key, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.serialNo)) { + isvParams.setSerialNo(StringKit.str2Star(this.serialNo, 4, 4, 6)); + } + return ((JSONObject)JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvsubMchParams.java new file mode 100644 index 0000000..61c0922 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sftpay/SftpayIsvsubMchParams.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model.params.sftpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 微信官方支付 配置参数 + * + * @author zhuxiao + * + * @date 2021/6/8 18:02 + */ +@Data +public class SftpayIsvsubMchParams extends IsvsubMchParams { + + /** 子商户ID **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subMchId; + + /** 子账户appID **/ + private String subMchAppId; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayConfig.java new file mode 100644 index 0000000..5fee554 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayConfig.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.params.shengpay; + +import lombok.Data; + +/* + * 盛付通 通用配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class ShengpayConfig { + + /** 网关地址 */ + public static String PROD_SERVER_URL = "http://mchapi.shengpay.com"; + public static String SANDBOX_SERVER_URL = "http://mchapitest.shengpay.com"; + + /** 智能pos 网关地址 */ + public static String AUTO_POS_PROD_SERVER_URL = "https://terminalflexiblelink.shengpay.com"; + public static String AUTO_POS_SANDBOX_SERVER_URL = "https://terminalflexiblelinktest.shengpay.com"; + + public static final String CNY ="CNY"; + public static final String DEFAULT_CHARSET = "UTF-8"; + + /** 创建 */ + public static String PAY_INIT = "PAY_INIT"; + /** 支付中 */ + public static String PAY_ING = "PAY_ING"; + /** 支付成功 */ + public static String PAY_SUCCESS = "PAY_SUCCESS"; + /** 支付失败 */ + public static String PAY_FAIL = "PAY_FAIL"; + /** 返回成功状态 */ + public static String RETURN_SUCCESS = "SUCCESS"; + /** 返回失败状态 */ + public static String RETURN_FAIL = "FAIL"; + /** 部分退款中 */ + public static String REFUND_PART_ING = "REFUND_PART_ING"; + public static String REFUND_PART_SUCCESS = "REFUND_PART_SUCCESS"; + /** 退款中 */ + public static String REFUND_ING = "REFUND_ING"; + /** 退款成功 */ + public static String REFUND_SUCCESS = "REFUND_SUCCESS"; + /** 退款失败 */ + public static String REFUND_FAIL = "REFUND_FAIL"; + /** 已取消 */ + public static String CLOSED = "CLOSED"; + + /** 智能POS通知 支付中 */ + public static String POS_PAY_ING = "ING"; + /** 智能POS通知 支付成功 */ + public static String POS_PAY_SUCCESS = "SUCCESS"; + /** 智能POS通知 支付失败 */ + public static String POS_PAY_FAIL = "FAIL"; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvParams.java new file mode 100644 index 0000000..bc59577 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.params.shengpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 盛付通 配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class ShengpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** mchId **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String mchId; + + /** privateKey 私钥 **/ + private String privateKey; + + /** 应用公钥(分账使用)**/ + private String appPublicKey; + + /** publicKey 盛付通公钥 **/ + private String publicKey; + + /** 小程序appId **/ + private String wxLiteAppId; + + @Override + public String deSenData() { + + ShengpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.str2Star(this.privateKey, 0, 3, 6)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.str2Star(this.publicKey, 6, 6, 6)); + } + if (StringUtils.isNotBlank(this.appPublicKey)) { + isvParams.setAppPublicKey(StringKit.str2Star(this.appPublicKey, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvsubMchParams.java new file mode 100644 index 0000000..1471fa3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayIsvsubMchParams.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.params.shengpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 盛付通 配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class ShengpayIsvsubMchParams extends IsvsubMchParams { + + // 子商户号 + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subMchId; + + + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + /** 退款挂起(如果挂起,退款余额不足时会挂起,有余额后会自动退款) **/ + private String isComplement; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayNormalMchParams.java new file mode 100644 index 0000000..f85d7d6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/shengpay/ShengpayNormalMchParams.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.params.shengpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 盛付通 普通商户配置 + * + * @author jmdhappy + * + * @date 2021/12/13 16:00 + */ +@Data +public class ShengpayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** mchId **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchId; + + /** privateKey 私钥 **/ + private String privateKey; + + /** publicKey 盛付通公钥 **/ + private String publicKey; + + /** 小程序appId **/ + private String wxLiteAppId; + + /** 退款挂起(如果挂起,退款余额不足时会挂起,有余额后会自动退款) **/ + private String isComplement; + + @Override + public String deSenData() { + + ShengpayNormalMchParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.str2Star(this.privateKey, 0, 3, 6)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.str2Star(this.publicKey, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayConfig.java new file mode 100644 index 0000000..f036218 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayConfig.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.params.sqbpay; +/** + * 收钱吧 通用配置信息 + */ +public class SqbpayConfig { + //接口名称 + public static String API_DOMAIN = "https://vsi-api.shouqianba.com"; //收钱吧接入域名 + public static String TERMINAL_CHECKIN = "/terminal/checkin"; //签到 + public static String UPAY_V2_PAY = "/upay/v2/pay"; //付款码支付 + public static String UPAY_V2_PRECREATE = "/upay/v2/precreate"; //预下单支付 + public static String UPAY_V2_REFUND = "/upay/v2/refund"; //退款 + public static String UPAY_V2_CANCEL = "/upay/v2/cancel"; //撤单 + public static String UPAY_V2_QUERY = "/upay/v2/query"; //查询 + public static String TERMINAL_ACTIVATE = "/terminal/activate"; //激活接口 + + public static String RESPONSE_STATE_SUCCESS = "200"; //成功响应状态 + + public static String RESPONSE_PAY_STATE_SUCCESS = "PAY_SUCCESS"; //订单成功状态 + public static String RESPONSE_PAY_STATE_ING = "PAY_IN_PROGRESS"; //订单支付中 + public static String RESPONSE_PAY_STATE_FAIL = "PAY_FAIL"; //订单交易失败 + public static String RESPONSE_PAY_STATE_INVALID_PARAMS = "INVALID_PARAMS"; //订单支付失败 + + public static String RESPONSE_PRECREATE_SUCCESS = "PRECREATE_SUCCESS"; //订单预下单成功 + + //网关地址 + public static String GATEWAY= "https://qr.shouqianba.com/gateway"; + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvParams.java new file mode 100644 index 0000000..61f6921 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvParams.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.core.model.params.sqbpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 收钱吧 服务商配置 + * + * @author xiaoyu + * + * @date 2022/3/8 14:45 + */ +@Data +public class SqbpayIsvParams extends IsvParams { + + /** 开发者序列号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String vendorSn; + + /** 开发者序秘钥 */ + private String vendorKey; + + /** 应用ID */ + private String appId; + + /** 收钱吧公钥 */ + private String publicKey; + + @Override + public String deSenData() { + SqbpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvsubMchParams.java new file mode 100644 index 0000000..399ca3d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sqbpay/SqbpayIsvsubMchParams.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.params.sqbpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 收钱吧 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/4/13 17:23 + */ +@Data +public class SqbpayIsvsubMchParams extends IsvsubMchParams { + + /** 应用配置参数 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String code; + + /** 终端设备号 **/ + private String terminalSn; + + /** 终端设备秘钥 **/ + private String terminalKey; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sumapay/SumapayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sumapay/SumapayNormalMchParams.java new file mode 100644 index 0000000..b2be525 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sumapay/SumapayNormalMchParams.java @@ -0,0 +1,53 @@ +package com.jeequan.jeepay.core.model.params.sumapay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 丰付支付 配置参数 + * + * @author zx + * + * @date 2022/11/23 18:02 + */ +@Data +public class SumapayNormalMchParams extends NormalMchParams { + + + /** + * 环境配置:0-生产环境,1-沙箱环境 + */ + private Byte sandbox; + + /** + * 商户编号 + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantCode; + + /** + * 业务类型代码 + */ + private String totalBizType; + + /** + * 密钥 + */ + private String md5Key; + + @Override + public String deSenData() { + SumapayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.md5Key)) { + mchParams.setMd5Key(StringKit.autoDesensitization(this.md5Key)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayConfig.java new file mode 100644 index 0000000..a5e5f64 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayConfig.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.core.model.params.sxfpay; + +import lombok.Data; + +/* + * 随行付 通用配置信息 + * + * @author zx + * + * @date 2023/5/22 18:02 + */ +@Data +public class SxfpayConfig { + + /** 网关地址 */ + public static String PROD_SERVER_URL = "https://openapi.tianquetech.com"; + public static String SANDBOX_SERVER_URL = "https://openapi-test.tianquetech.com"; + + /** 下载对账单地址 */ + public static String URI_BILL_DOWNLOAD = "/capital/fileDownload/getFileUrl"; + + public static final String CNY ="CNY"; + public static final String DEFAULT_CHARSET = "UTF-8"; + + /** 请求成功状态 */ + public static String REQ_SUCCESS = "0000"; + + /** 业务成功状态 */ + public static String BIZ_SUCCESS = "0000"; + + /** 下载账单 业务成功状态 */ + public static String BIZ_BILL_SUCCESS = "00"; + + /** 支付中,带查询状态 */ + public static String PAY_WAIT_QUERY = "2002"; + + /** 支付中 */ + public static String PAY_ING = "PAYING"; + /** 支付成功 */ + public static String PAY_SUCCESS = "SUCCESS"; + /** 支付失败 */ + public static String PAY_FAIL = "FAIL"; + /** 已关闭 */ + public static String CLOSED = "CLOSED"; + /** 已撤销 */ + public static String CANCELED = "CANCELED"; + + /** 退款中 */ + public static String REFUND_ING = "REFUNDING"; + /** 退款成功 */ + public static String REFUND_SUCCESS = "REFUNDSUC"; + /** 退款失败 */ + public static String REFUND_FAIL = "REFUNDFAIL"; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvParams.java new file mode 100644 index 0000000..0f6a753 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvParams.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.params.sxfpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 随行付 配置信息 + * + * @author zx + * + * @date 2023/5/22 18:02 + */ +@Data +public class SxfpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 天阙平台机构号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String orgId; + + /** privateKey 私钥 **/ + private String privateKey; + + /** publicKey 随行付公钥 **/ + private String publicKey; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + @Override + public String deSenData() { + + SxfpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(this.privateKey)); + } + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvsubMchParams.java new file mode 100644 index 0000000..dec6db8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/sxfpay/SxfpayIsvsubMchParams.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.params.sxfpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 随行付 配置信息 + * + * @author zx + * + * @date 2023/5/22 18:02 + */ +@Data +public class SxfpayIsvsubMchParams extends IsvsubMchParams { + + /** 子商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mno; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvParams.java new file mode 100644 index 0000000..1e098e9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvParams.java @@ -0,0 +1,75 @@ +package com.jeequan.jeepay.core.model.params.terpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +/** + * 国通星驿 服务商参数定义 + * + * @author yr + * + * @date 2022/10/17 16:00 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class TerpayIsvParams extends IsvParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 机构号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String agetId; + + /** 机构APPID */ + private String agetAppid; + + /** 服务商的微信公众号AppSecret[用于公众号AppId配置] */ + private String wxJsapiAppSecret; + + /** 服务商的微信小程序AppSecret[用于小程序AppId配置] */ + private String wxLiteAppSecret; + + /** + * 服务商机构标识码 银联 备注:之前交易已经在三方配好的,这个字段可以不上送 + */ + private String fpid; + + /** 传输公钥 */ + private String publicKey; + + /** 免签免密结算费率 % **/ + private String ratePosM; + + /** 云闪付结算费率 % **/ + private String ratePosS; + + /** 微信开户意愿地址 */ + private String wxUrl; + + /** 支付宝商家认证地址 */ + private String aliUrl; + + + @Override + public String deSenData() { + TerpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(this.publicKey)); + } + if (StringUtils.isNotBlank(this.wxJsapiAppSecret)) { + isvParams.setWxJsapiAppSecret(StringKit.autoDesensitization(this.wxJsapiAppSecret)); + } + if (StringUtils.isNotBlank(this.wxLiteAppSecret)) { + isvParams.setWxLiteAppSecret(StringKit.autoDesensitization(this.wxLiteAppSecret)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvsubMchParams.java new file mode 100644 index 0000000..76c2496 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/terpay/TerpayIsvsubMchParams.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.params.terpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 国通星驿 特约商户参数定义 + * + * @author yr + * + * @date 2022/10/17 16:00 + */ +@Data +public class TerpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户编号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String custId; + /** 商户进件时填的手机号 */ + private String custLogin; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + /** 设备号(进件时会生成,若没有则随便传一个) */ + private String driveNo; + + public String deSenData() { + TerpayIsvsubMchParams terpayIsvsubMchParams = this; + return ((JSONObject) JSON.toJSON(terpayIsvsubMchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvParams.java new file mode 100644 index 0000000..837c216 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvParams.java @@ -0,0 +1,57 @@ +package com.jeequan.jeepay.core.model.params.umhspay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商配置参数 + * + * @author xiaoyu + * + * @date 2022/11/15 9:23 + */ +@Data +public class UmhspayIsvParams extends IsvParams { + + /** 合作方ID */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String partnerId; + + /** AES密钥 **/ + private String aesKey; + + /** 商户私钥 **/ + private String privateKey; + + /** 联动平台公钥 **/ + private String publicKey; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + + + @Override + public String deSenData() { + UmhspayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.aesKey)) { + isvParams.setAesKey(StringKit.autoDesensitization(isvParams.aesKey)); + } + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvsubMchParams.java new file mode 100644 index 0000000..d9bcb39 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umhspay/UmhspayIsvsubMchParams.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.params.umhspay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/9/13 15:43 + */ +@Data +public class UmhspayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantId; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvParams.java new file mode 100644 index 0000000..de4876b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvParams.java @@ -0,0 +1,61 @@ +package com.jeequan.jeepay.core.model.params.umpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** + * 服务商配置参数 + * + * @author xiaoyu + * + * @date 2022/11/15 9:23 + */ +@Data +public class UmpayIsvParams extends IsvParams { + + /** 环境配置 1-沙箱环境 0-生产环境 **/ + private Byte sandbox; + + /** appId */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String appId; + + /** 应用私钥 **/ + private String privateKey; + + /** 联动公钥 **/ + private String publicKey; + + /** 微信开通意愿二维码url */ + private String wxOpenUrl; + + /** 支付宝开通意愿二维码url */ + private String aliChannelExtUrl; + + /** 微信渠道号 (多渠道时上送) */ + private String wxChannelNo; + + /** 支付宝渠道号 (多渠道时上送) */ + private String aliChannelNo; + + + @Override + public String deSenData() { + + UmpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.privateKey)) { + isvParams.setPrivateKey(StringKit.autoDesensitization(isvParams.privateKey)); + } + if (StringUtils.isNotBlank(isvParams.publicKey)) { + isvParams.setPublicKey(StringKit.autoDesensitization(isvParams.publicKey)); + } + + return JSONObject.toJSONString(isvParams); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvsubMchParams.java new file mode 100644 index 0000000..cbd33be --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/umpay/UmpayIsvsubMchParams.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.params.umpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/9/13 15:43 + */ +@Data +public class UmpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 storeId **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String storeId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayConfig.java new file mode 100644 index 0000000..1f70eb4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayConfig.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.params.unionpay; + +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; + +/* + * 银联支付, 通用配置信息 + * + * @author jmdhappy + * + * @date 2021/12/1 10:32 + */ +@Data +public class UnionpayConfig{ + + /** 网关地址 */ + public static String PROD_SERVER_URL = "https://gateway.95516.com"; + public static String SANDBOX_SERVER_URL = "https://gateway.test.95516.com"; + + /** 默认配置的是UTF-8 */ + public static String ENCODING = "UTF-8"; + + /** 版本号 固定值 5.1.0 */ + public static String VERSION = "5.1.0"; + + /** 签名方法 非对称签名: 01(表示采用RSA签名) HASH表示散列算法 11:支持散列方式验证SHA-256 12:支持散列方式验证SM3 */ + public static String SIGN_METHOD = "01"; + + public static String getServerUrl(Byte sandbox) { + return sandbox == CS.YES ? SANDBOX_SERVER_URL : PROD_SERVER_URL; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayNormalMchParams.java new file mode 100644 index 0000000..1bc49eb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/unionpay/UnionpayNormalMchParams.java @@ -0,0 +1,48 @@ +package com.jeequan.jeepay.core.model.params.unionpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import lombok.Data; + +/* + * 银联支付 普通商户参数定义 + * + * @author jmdhappy + * + * @date 2021/12/01 10:51 + */ +@Data +public class UnionpayNormalMchParams extends NormalMchParams { + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merId; + + /** 敏感加密证书 */ + private String encryptCert; + + /** 商户私钥证书,签名使用 */ + private String merPrivateCert; + + /** 商户私钥证书密码 */ + private String merPrivateCertPwd; + + /** 验签中级证书 */ + private String unionMiddleCert; + + /** 验签根证书 */ + private String unionRootCert; + + @Override + public String deSenData() { + UnionpayNormalMchParams mchParams = this; + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayConfig.java new file mode 100644 index 0000000..3b83059 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayConfig.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.params.utmpay; + +import com.jeequan.jeepay.core.constants.CS; + +import java.util.HashMap; +import java.util.Map; + +/* + * 银联条码支付前置 配置 + * + * @author zx + * + * @date 2022/6/20 18:02 + */ +public class UtmpayConfig { + + public static String BASE_URL_PAY = "https://qra.95516.com/pay/gateway"; // 支付域名 + + public static String BASE_URL_APPLY = "https://up.95516.com/interface/gateway"; // 进件域名 + + public static String charset = "UTF-8"; // 编码 + + public static String WX_API_CODE = "pay.weixin.jspay"; // 微信jsapi apiCode编码,查询交易识别码使用 + + // 支付类型(暂时写死为 易票联标准通道) + // 实际取值请联系技术支持获取,每个行不一样。可以通过管理平台"机构管理"->"机构进件管理"页面上的“机构支付类型配置信息”中查看。 + // 文档地址:https://up.95516.com/open/openapi/doc?index_1=127&index_2=1&chapter_1=1943&chapter_2=1945 + public static Map yplPayWayMap = new HashMap<>(); + static { + yplPayWayMap.put(CS.PAY_WAY_CODE.WX_JSAPI, "10000861"); + yplPayWayMap.put(CS.PAY_WAY_CODE.WX_LITE, "10000861"); + yplPayWayMap.put(CS.PAY_WAY_CODE.WX_BAR, "10000862"); + yplPayWayMap.put(CS.PAY_WAY_CODE.WX_NATIVE, "10000863"); + yplPayWayMap.put(CS.PAY_WAY_CODE.ALI_JSAPI, "10000868"); + yplPayWayMap.put(CS.PAY_WAY_CODE.ALI_LITE, "10000868"); + yplPayWayMap.put(CS.PAY_WAY_CODE.ALI_BAR, "10000869"); + yplPayWayMap.put(CS.PAY_WAY_CODE.ALI_QR, "10000870"); + yplPayWayMap.put(CS.PAY_WAY_CODE.UP_JSAPI, "10032212"); + yplPayWayMap.put(CS.PAY_WAY_CODE.UP_BAR, "10001311"); + yplPayWayMap.put(CS.PAY_WAY_CODE.UP_QR, "10001312"); + yplPayWayMap.put(CS.PAY_WAY_CODE.YSF_BAR, "10001311"); + yplPayWayMap.put(CS.PAY_WAY_CODE.YSF_JSAPI, "10032212"); + } + + + public static String SUCCESS_STATUS_CODE = "0"; // 0表示成功,非0表示失败此字段是通信标识,非交易标识,交易是否成功需要查看 result_code 、pay_result共同来判断 + public static String SUCCESS_RESULT_CODE = "0"; // 0表示成功,非0表示失败,交易终态请以pay_result为准 + public static String SUCCESS_PAY_RESULT_CODE = "0"; // 支付结果:0—成功;其它—失败(支付结果以此字段为准) + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvParams.java new file mode 100644 index 0000000..7afdc26 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvParams.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.core.model.params.utmpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 银联条码支付前置 配置信息 + * + * @author zx + * + * @date 2022/6/20 18:02 + */ +@Data +public class UtmpayIsvParams extends IsvParams { + + /** 机构号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String partner; + + /** md5Key 密钥 **/ + private String md5Key; + + /** 申请服务商的 公众号的 appID */ + private String appId; + + /** 小程序的 appID */ + private String liteAppId; + + @Override + public String deSenData() { + + UtmpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.md5Key)) { + isvParams.setMd5Key(StringKit.autoDesensitization(this.md5Key)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvsubMchParams.java new file mode 100644 index 0000000..03cce97 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/utmpay/UtmpayIsvsubMchParams.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.params.utmpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 银联条码支付前置 配置信息 + * + * @author zx + * + * @date 2022/6/20 18:02 + */ +@Data +public class UtmpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merchantId; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + /** 子商户App软件微信开放平台中AppId(使用app支付必填) **/ + private String subMchOpenAppId; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvParams.java new file mode 100644 index 0000000..d25bc4f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvParams.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.core.model.params.wxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 微信官方支付 配置参数 +* +* @author zhuxiao +* +* @date 2021/6/8 18:02 +*/ +@Data +public class WxpayIsvParams extends IsvParams { + + /** 申请服务商的 公众号的 appID */ + private String appId; + + /** 微信支付商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String mchId; + + /** oauth2地址 */ + private String oauth2Url; + + /** API密钥 */ + private String key; + + /** 签名方式 **/ + private String signType; + + /** 微信支付API版本 **/ + private String apiVersion; + + /** API V3秘钥 **/ + private String apiV3Key; + + /** 序列号 **/ + private String serialNo; + + /** API证书(.p12格式)**/ + private String cert; + + /** 证书文件(.pem格式) **/ + private String apiClientCert; + + /** 私钥文件(.pem格式) **/ + private String apiClientKey; + + + + + @Override + public String deSenData() { + + WxpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.key)) { + isvParams.setKey(StringKit.str2Star(this.key, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.apiV3Key)) { + isvParams.setApiV3Key(StringKit.str2Star(this.apiV3Key, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.serialNo)) { + isvParams.setSerialNo(StringKit.str2Star(this.serialNo, 4, 4, 6)); + } + return ((JSONObject)JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvsubMchParams.java new file mode 100644 index 0000000..3c04eea --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayIsvsubMchParams.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.params.wxpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 微信官方支付 配置参数 + * + * @author zhuxiao + * + * @date 2021/6/8 18:02 + */ +@Data +public class WxpayIsvsubMchParams extends IsvsubMchParams { + + /** 子商户ID **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String subMchId; + + /** 子商户公众号AppId(置空表示使用服务商) **/ + private String subMchAppId; + + /** 子商户小程序AppId(置空表示使用服务商) **/ + private String subMchLiteAppId; + + /** 子商户App软件微信开放平台中AppId(使用app支付必填) **/ + private String subMchOpenAppId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayNormalMchParams.java new file mode 100644 index 0000000..59bca0e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/wxpay/WxpayNormalMchParams.java @@ -0,0 +1,106 @@ +package com.jeequan.jeepay.core.model.params.wxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 微信官方支付 配置参数 + * + * @author zhuxiao + * + * @date 2021/6/8 18:02 + */ +@Data +public class WxpayNormalMchParams extends NormalMchParams { + + /** + * 应用App ID + */ + private String appId; + + /** + * 应用AppSecret + */ + private String appSecret; + + /** 小程序的 appID */ + private String liteAppId; + + /** 小程序的 AppSecret */ + private String liteAppSecret; + + /** 商户App软件微信开放平台中AppId(使用app支付必填) **/ + private String openAppId; + + /** + * 微信支付商户号 + */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchId; + + /** + * oauth2地址 + */ + private String oauth2Url; + + /** + * API密钥 + */ + private String key; + + /** + * 微信支付API版本 + **/ + private String apiVersion; + + /** + * API V3秘钥 + **/ + private String apiV3Key; + + /** + * 序列号 + **/ + private String serialNo; + + /** + * API证书(.p12格式) + **/ + private String cert; + + /** 证书文件(.pem格式) **/ + private String apiClientCert; + + /** + * 私钥文件(.pem格式) + **/ + private String apiClientKey; + + @Override + public String deSenData() { + WxpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.appSecret)) { + mchParams.setAppSecret(StringKit.str2Star(this.appSecret, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.liteAppSecret)) { + mchParams.setLiteAppSecret(StringKit.str2Star(this.liteAppSecret, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.key)) { + mchParams.setKey(StringKit.str2Star(this.key, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.apiV3Key)) { + mchParams.setApiV3Key(StringKit.str2Star(this.apiV3Key, 4, 4, 6)); + } + if (StringUtils.isNotBlank(this.serialNo)) { + mchParams.setSerialNo(StringKit.str2Star(this.serialNo, 4, 4, 6)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/xxpay/XxpayNormalMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/xxpay/XxpayNormalMchParams.java new file mode 100644 index 0000000..1d067cc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/xxpay/XxpayNormalMchParams.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.model.params.xxpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.NormalMchParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 小新支付 普通商户参数定义 + * + * @author jmdhappy + * + * @date 2021/9/10 21:51 + */ +@Data +public class XxpayNormalMchParams extends NormalMchParams { + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mchId; + + /** 私钥 */ + private String key; + + /** 支付网关地址 */ + private String payUrl; + + @Override + public String deSenData() { + XxpayNormalMchParams mchParams = this; + if (StringUtils.isNotBlank(this.key)) { + mchParams.setKey(StringKit.str2Star(this.key, 4, 4, 6)); + } + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ybpay/YbpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ybpay/YbpayIsvParams.java new file mode 100644 index 0000000..23feedc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ybpay/YbpayIsvParams.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.params.ybpay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +/** + * 易宝 isv参数定义 + * + * @author xiaoyu + * @site https://www.jeequan.com + * @date 2022/7/8 11:02 + */ +@Data +public class YbpayIsvParams extends IsvParams { + + /** 加密方式 RSA/SM */ + private String signType; + + /** + * 易宝APPId + */ + private String appId; + + /** + * 摘要 + */ + private String keyContent; + + + private String privateKey; + + + private String publicKey; + + + private String privateKeyFile; + + + private String publicKeyFile; + + @Override + public String deSenData() { + YbpayIsvParams isvParams = this; + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayConfig.java new file mode 100644 index 0000000..2635914 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayConfig.java @@ -0,0 +1,20 @@ +package com.jeequan.jeepay.core.model.params.ysf; + +import lombok.Data; + +/* + * 云闪付 通用配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class YsfpayConfig { + + + /** 网关地址 */ + public static String PROD_SERVER_URL = "https://partner.95516.com"; + public static String SANDBOX_SERVER_URL = "http://ysf.bcbip.cn:10240"; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvParams.java new file mode 100644 index 0000000..70bcfc2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvParams.java @@ -0,0 +1,95 @@ +package com.jeequan.jeepay.core.model.params.ysf; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.params.IsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 云闪付 配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class YsfpayIsvParams extends IsvParams { + + // 瑞银信 + public static final String ACQ_ORG_CODE_RYX = "RYX"; + // 中付 + public static final String ACQ_ORG_CODE_ZF = "ZF"; + // 其他 + public static final String ACQ_ORG_CODE_COMMONS = "COMMONS"; + + /** 是否沙箱环境 */ + private Byte sandbox; + + /** 银联服务商标识 serProvId **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String serProvId; + + /** 服务商机构标识码 pnrInsIdCd **/ + private String pnrInsIdCd; + + /** isvPrivateCertFile 证书 **/ + private String isvPrivateCertFile; + + /** isvPrivateCertPwd **/ + private String isvPrivateCertPwd; + + /** ysfpayPublicKey **/ + private String ysfpayPublicKey; + + /** acqOrgCodeList 支付机构号 **/ + private JSONArray acqOrgCodeList; + + @Override + public String deSenData() { + + YsfpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(this.isvPrivateCertPwd)) { + isvParams.setIsvPrivateCertPwd(StringKit.str2Star(this.isvPrivateCertPwd, 0, 3, 6)); + } + if (StringUtils.isNotBlank(this.ysfpayPublicKey)) { + isvParams.setYsfpayPublicKey(StringKit.str2Star(this.ysfpayPublicKey, 6, 6, 6)); + } + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } + + /** + * @author: xiaoyu + * @date: 2022/4/28 14:52 + * @describe: 获取对应支付机构类型的支付机构号 + */ + public String getOrgCode(String acqOrgType) { + try { + if (this.acqOrgCodeList == null) return null; + + for (int i = 0; i < this.acqOrgCodeList.size(); i++) { + OrgCodeInfo codeInfo = JSONObject.parseObject(this.acqOrgCodeList.get(i).toString(), YsfpayIsvParams.OrgCodeInfo.class); + if (acqOrgType.equals(codeInfo.getAcqOrgCodeType())) { + return codeInfo.getAcqOrgCode(); + } + } + return null; + }catch (BizException e) { + throw new BizException(e.getMessage()); + } + } + + @Data + public static class OrgCodeInfo { + // 机构类型 + private String acqOrgCodeType; + // 机构号 + private String acqOrgCode; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvsubMchParams.java new file mode 100644 index 0000000..d50e096 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/ysf/YsfpayIsvsubMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.ysf; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 云闪付 配置信息 + * + * @author pangxiaoyu + * + * @date 2021/6/8 18:02 + */ +@Data +public class YsfpayIsvsubMchParams extends IsvsubMchParams { + + /** 云闪付商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String merId; + + /** 收单机构商户号 **/ + private String acqMerId; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvParams.java new file mode 100644 index 0000000..b7aa264 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvParams.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.core.model.params.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvParams; +import lombok.Data; + +/** + * 银盛 isv参数定义 + * + * @author xiaoyu + * @site https://www.jeequan.com + * @date 2022/7/8 11:02 + */ +@Data +public class YspayIsvParams extends IsvParams { + + public static final Byte PAY_TYPE_PAY = 1; + public static final Byte PAY_TYPE_DIVISION = 2; + + /** 加密方式 RSA/SM */ + private String signType; + + /** 结算方式 1- T1 2-D1 3-D0 */ + private String settType; + + /** 服务商号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.ISV_NO) + private String partnerId; + + /** 服务商编号 */ + private String agtMercId; + + /** */ + private String cusMgrNm; + + /** 微信渠道拓展二维码URL */ + private String wxOpenUrl; + + /** 微信公众号/小程序 appId **/ + private String wxAppId; + + /** 支付宝渠道拓展二维码URL **/ + private String aliChannelExtUrl; + + /** 银盛机构号 【已废弃】*/ + private String src; + + /** POS秘钥 */ + private String posPrivateKey; + + /** 私钥证书秘钥 */ + private String privateKeyPassword; + + /** 私钥证书文件 (.pfx/.sm2) */ + private String privateKeyFile; + + /** 银盛公钥证书文件 (.cer) */ + private String publicKeyFile; + + /** 商户支付模式 支付模式,分账模式 1,2*/ + private String payType; + + @Override + public String deSenData() { + YspayIsvParams isvParams = this; + return ((JSONObject) JSON.toJSON(isvParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvsubMchParams.java new file mode 100644 index 0000000..17619f8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/yspay/YspayIsvsubMchParams.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.params.yspay; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/** + * 银盛 特约商户参数定义 + * + * @author xiaoyu + * + * @date 2022/7/8 11:02 + */ +@Data +public class YspayIsvsubMchParams extends IsvsubMchParams { + + /** 商户支付分账模式 **/ + public static final Byte PAY_TYPE_PAY = 1; + public static final Byte PAY_TYPE_DIVISION = 2; + + /** 商户号 */ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String mercId; + + /** 商户支付模式 1-支付 2-分账 */ + private Byte payType; + + public String deSenData() { + YspayIsvsubMchParams mchParams = this; + + return ((JSONObject) JSON.toJSON(mchParams)).toJSONString(); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvParams.java new file mode 100644 index 0000000..c055746 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvParams.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.model.params.zftpay; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams; +import com.jeequan.jeepay.core.utils.StringKit; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 支付宝直付通 isv参数定义 +* +* @author terrfly +* +* @date 2021/6/8 16:34 +*/ +@Data +public class ZftpayIsvParams extends AlipayIsvParams { + + /** 结算方式 */ + private String settType; + + /** 结算时间类型 */ + private String settDayType; + + /** 结算时间天数 */ + private int settDay; + + @Override + public String deSenData() { + + ZftpayIsvParams isvParams = this; + if (StringUtils.isNotBlank(isvParams.getPrivateKey())) { + isvParams.setPrivateKey(StringKit.str2Star(isvParams.getPrivateKey(), 4, 4, 6)); + } + if (StringUtils.isNotBlank(isvParams.getAlipayPublicKey())) { + isvParams.setAlipayPublicKey(StringKit.str2Star(isvParams.getAlipayPublicKey(), 6, 6, 6)); + } + + return JSONObject.toJSONString(isvParams); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvsubMchParams.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvsubMchParams.java new file mode 100644 index 0000000..86b9639 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/params/zftpay/ZftpayIsvsubMchParams.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.params.zftpay; + +import com.jeequan.jeepay.core.annotate.ChannelMchId; +import com.jeequan.jeepay.core.constants.ChannelMchIdTypeEnum; +import com.jeequan.jeepay.core.model.params.IsvsubMchParams; +import lombok.Data; + +/* + * 支付宝直付通 特约商户参数定义 + * + * @author terrfly + * + * @date 2021/6/8 16:33 + */ +@Data +public class ZftpayIsvsubMchParams extends IsvsubMchParams { + + /** 商户号 **/ + @ChannelMchId(type = ChannelMchIdTypeEnum.MCH_NO) + private String smid; + + /** 审核结果说明 **/ + private String fkAuditMemo; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractMchAppRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractMchAppRQ.java new file mode 100644 index 0000000..f4e3593 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractMchAppRQ.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.rqrs; + +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; + +/* +* +* 通用RQ, 包含mchNo和appId 必填项 +* +* @author terrfly +* +* @date 2021/6/16 10:30 +*/ +@Data +public abstract class AbstractMchAppRQ extends AbstractRQ { + + /** 商户号 **/ + @NotBlank(message="商户号不能为空") + private String mchNo; + + /** 商户应用ID **/ + @NotBlank(message="商户应用ID不能为空") + private String appId; + + /** + * 商户号 现在的进件申请单号 对应进件表的 applyId; + */ + private String mchExtNo; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRQ.java new file mode 100644 index 0000000..29d860c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRQ.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.core.model.rqrs; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/* +* 基础请求参数 +* +* @author terrfly +* +* @date 2021/6/8 17:39 +*/ +@Data +public abstract class AbstractRQ implements Serializable { + + /** 版本号 **/ + @NotBlank(message="版本号不能为空") + protected String version; + + /** 签名类型 **/ + @NotBlank(message="签名类型不能为空") + protected String signType; + + /** 签名值 **/ + @NotBlank(message="签名值不能为空") + protected String sign; + + /** 接口请求时间 **/ + @NotBlank(message="时间戳不能为空") + protected String reqTime; + + /** platformApiSecret 平台通信秘钥 简写。 无需在API文档中体现, 命名尽量混淆。 **/ + protected String pas; + + /** 当前接口的名称, 用作权限的验证 **/ + public abstract String apiName(); + + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRS.java new file mode 100644 index 0000000..8f55316 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/AbstractRS.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs; + +import com.alibaba.fastjson.JSON; +import lombok.Data; + +import java.io.Serializable; + +/* +* 接口抽象RS对象, 本身无需实例化 +* +* @author terrfly +* +* @date 2021/6/8 17:39 +*/ +@Data +public abstract class AbstractRS implements Serializable { + + public String toJSONString(){ + return JSON.toJSONString(this); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/ChannelUserIdRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/ChannelUserIdRQ.java new file mode 100644 index 0000000..b5a8deb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/ChannelUserIdRQ.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.rqrs; + +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* +* 商户获取渠道用户ID 请求参数对象 +* +* @author terrfly +* +* @date 2021/6/8 17:40 +*/ +@Data +public class ChannelUserIdRQ extends AbstractMchAppRQ{ + + /** 接口代码, AUTO表示:自动获取 **/ + @NotBlank(message="接口代码不能为空") + private String ifCode; + + /** 商户扩展参数,将原样返回 **/ + private String extParam; + + /** 回调地址 **/ + @NotBlank(message="回调地址不能为空") + private String redirectUrl; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_CHANNEL_USER; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRQ.java new file mode 100644 index 0000000..d6ecf96 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRQ.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; +import org.hibernate.validator.constraints.Range; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/* +* 分账账号的绑定 请求参数 +* +* @author terrfly +* +* @date 2021/8/25 09:21 +*/ +@Data +public class DivisionReceiverBindRQ extends AbstractMchAppRQ { + + /** 支付接口代码 **/ + @NotBlank(message="所属通道[ifCode]不能为空") + private String ifCode; + + @NotBlank(message="所属渠道号[isvNo]不能为空") + private String isvNo; + + /** 接收者账号别名 **/ + private String receiverAlias; + + /** 分账接收账号类型: 0-个人(对私) 1-商户(对公) **/ + @NotNull(message="分账接收账号类型不能为空") + @Range(min = 0, max = 1, message = "账号类型[accType]有误") + private Byte accType; + + /** 分账接收账号 **/ + @NotBlank(message="分账接收账号不能为空") + private String accNo; + + /** 分账接收账号名称 **/ + private String accName; + + /** 扩展参数 */ + private JSONObject extInfo; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_DIVISION_BIND; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRS.java new file mode 100644 index 0000000..261b461 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverBindRS.java @@ -0,0 +1,116 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.entity.DivisionSubjectEx; +import com.jeequan.jeepay.core.entity.MchDivisionReceiver; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +import java.math.BigDecimal; + +/* +* 绑定账户 响应参数 +* +* @author terrfly +* +* @date 2021/6/8 17:34 +*/ +@Data +public class DivisionReceiverBindRS extends AbstractRS { + + + /** + * 分账接收者ID + */ + private Long receiverId; + + /** + * 接收者账号别名 + */ + private String receiverAlias; + + /** + * 组ID(便于商户接口使用) + */ + private Long receiverGroupId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 应用ID + */ + private String appId; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 分账接收账号类型: 0-个人(对私) 1-商户(对公) + */ + private Byte accType; + + /** + * 分账接收账号 + */ + private String accNo; + + /** + * 分账接收账号名称 + */ + private String accName; + + /** + * 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等 + */ + private String relationType; + + /** + * 当选择自定义时,需要录入该字段。 否则为对应的名称 + */ + private String relationTypeName; + + + /** + * 渠道特殊信息 + */ + private String channelExtInfo; + + /** + * 绑定成功时间 + */ + private Long bindSuccessTime; + + /** + * 分账比例 + */ + private BigDecimal divisionProfit; + + /** + * 分账状态 1-绑定成功, 0-绑定异常 + */ + private Byte bindState; + + /** + * 支付渠道错误码 + */ + private String errCode; + + /** + * 支付渠道错误信息 + */ + private String errMsg; + + public static DivisionReceiverBindRS buildByRecord(DivisionSubjectEx subjectEx){ + if(subjectEx == null){ + return null; + } + DivisionReceiverBindRS result = new DivisionReceiverBindRS(); + BeanUtils.copyProperties(subjectEx, result); + return result; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRQ.java new file mode 100644 index 0000000..20ef951 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRQ.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * 分账账号 渠道余额提现 + * + * @author terrfly + * + * @date 2022/05/11 10:46 + */ +@Data +public class DivisionReceiverChannelBalanceCashoutRQ extends AbstractMchAppRQ { + + /** 分账接收者ID **/ + @NotNull(message="分账接收者ID不能为空") + private Long receiverId; + + /** 提现金额 **/ + @NotNull(message="提现金额不能为空") + @Min(value = 1, message = "提现金额请大于1") + private Long cashoutAmount; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_DIVISION_CHANNEL_CASHOUT; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRS.java new file mode 100644 index 0000000..ac52d77 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceCashoutRS.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; + +/** + * 分账账号 渠道余额提现 + * + * @author terrfly + * + * @date 2022/05/11 10:46 + */ +@Data +public class DivisionReceiverChannelBalanceCashoutRS extends AbstractRS { + + /** + * 分账接收者ID + */ + private Long receiverId; + + /** 提现状态: 1-成功, 0-失败 **/ + private Byte state; + + /** 渠道返回错误代码 **/ + private String errCode; + + /** 渠道返回错误信息 **/ + private String errMsg; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRQ.java new file mode 100644 index 0000000..1a2379b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRQ.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 分账账号 渠道余额查询 + * + * @author terrfly + * + * @date 2022/05/11 10:46 + */ +@Data +public class DivisionReceiverChannelBalanceQueryRQ extends AbstractMchAppRQ { + + /** 分账接收者ID **/ + @NotNull(message="分账接收者ID不能为空") + private Long receiverId; + + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_DIVISION_CHANNEL_BALANCE; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRS.java new file mode 100644 index 0000000..7743d43 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/DivisionReceiverChannelBalanceQueryRS.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; + +/** + * 分账账号 渠道余额查询 + * + * @author terrfly + * + * @date 2022/05/11 10:46 + */ +@Data +public class DivisionReceiverChannelBalanceQueryRS extends AbstractRS { + + /** + * 分账接收者ID + */ + private Long receiverId; + + /** 可用余额, 单位:分 **/ + private Long balanceAmount; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRQ.java new file mode 100644 index 0000000..2cebc82 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRQ.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/* +* 发起订单分账 请求参数 +* +* @author terrfly +* +* @date 2021/8/26 17:21 +*/ +@Data +public class PayOrderDivisionExecRQ extends AbstractMchAppRQ { + + /** 商户订单号 **/ + private String mchOrderNo; + + /** 支付系统订单号 **/ + private String payOrderId; + + /** + * 是否使用系统配置的自动分账组: 0-否 1-是 + **/ + @NotNull(message = "是否使用系统配置的自动分账组不能为空") + private Byte useSysAutoDivisionReceivers; + + /** 接收者账号列表(JSONArray 转换为字符串类型) + * 仅当useSysAutoDivisionReceivers=0 时有效。 + * + * 参考: + * + * 方式1: 按账号纬度 + * [{ + * receiverId: 800001, + * divisionProfit: 0.1 (若不填入则使用系统默认配置值) + * }] + * + * 方式2: 按组纬度 + * [{ + * receiverGroupId: 100001, (该组所有 当前订单的渠道账号并且可用状态的全部参与分账) + * divisionProfit: 0.1 (每个账号的分账比例, 若不填入则使用系统默认配置值, 建议不填写) + * }] + * + * **/ + private String receivers; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_DIVISION_EXEC; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRS.java new file mode 100644 index 0000000..15be1d0 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/division/PayOrderDivisionExecRS.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.core.model.rqrs.division; + +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; + +/** +* 发起订单分账 响应参数 +* +* @author terrfly +* +* @date 2021/8/26 17:20 +*/ +@Data +public class PayOrderDivisionExecRS extends AbstractRS { + + /** + * 分账状态 1-分账成功, 2-分账失败 + */ + private Byte state; + + /** + * 上游分账批次号 + */ + private String channelBatchOrderId; + + /** + * 支付渠道错误码 + */ + private String errCode; + + /** + * 支付渠道错误信息 + */ + private String errMsg; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/mch/ChannelMchRq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/mch/ChannelMchRq.java new file mode 100644 index 0000000..120c715 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/mch/ChannelMchRq.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.core.model.rqrs.mch; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * TODO + * + * @author crystal + * @date 2023/12/7 15:11 + */ +@Data +public class ChannelMchRq { + + private String appid; + + private String jsapiPath; + + /** + * 00:公众号 01:小程序 02:jsapi path设置 + */ + private String type; + + /** + * 子商户号 + */ + private String subMchNo; + + @Getter + @AllArgsConstructor + public enum Type{ + + PUBLIC("00"), + + APPLET("01"), + + PATH("02"); + + private final String type; + } + + public ChannelMchRq(String appid, String jsapiPath, String type,String subMchNo) { + this.appid = appid; + this.jsapiPath = jsapiPath; + this.type = type; + this.subMchNo = subMchNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelAppletPayMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelAppletPayMsg.java new file mode 100644 index 0000000..e8afb7a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelAppletPayMsg.java @@ -0,0 +1,50 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TODO + * + * @author crystal + * @date 2024/4/12 14:58 + */ +@Data +@NoArgsConstructor +public class ChannelAppletPayMsg { + + /** + * appid + */ + private String appId; + + /** + * 支付路径 + */ + private String path; + + /** + * 版本 + */ + private String envVersion; + /** + * 原始id + */ + private String ghId; + + /** + * 支付宝小程序码 + */ + private String alipayPath; + + public ChannelAppletPayMsg(String liteAppId, String path, String ghId, String liteEnv) { + this.appId = liteAppId; + this.path = path; + this.ghId = ghId; + this.envVersion = liteEnv; + } + + public ChannelAppletPayMsg(String alipayPath) { + this.alipayPath = alipayPath; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelJsapiMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelJsapiMsg.java new file mode 100644 index 0000000..d16d16e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelJsapiMsg.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * TODO + * jsapi 付款参数 + * @author crystal + * @date 2024/2/27 16:10 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +public class ChannelJsapiMsg { + + private String appId; + + private String timeStamp; + + private String nonceStr; + + @JSONField(name = "package") + private String payPackage; + + private String tradeNo; + + private String redirectUrl; + + private String paySign; + + private String signType; + +// private String partnerId; + + private String qrCodeUrl; + + public ChannelJsapiMsg(String tradeNo) { + this.tradeNo = tradeNo; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRefundLimit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRefundLimit.java new file mode 100644 index 0000000..5a4c981 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRefundLimit.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * TODO + * 退款权限 + * @author crystal + * @date 2024/3/20 11:39 + */ +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +public class ChannelRefundLimit { + + /** + * 已开通 + */ + public static final byte SUCCESS = 1; + + /** + * 未开通 + */ + public static final byte NO_OPEN = -1; + + /* + * 平台户 + */ + private Boolean isPlatAccount; + + /** + * 默认账户 + */ + private Boolean isDefaultAccount; + + /** + * 绑定状态 -1:未绑定退货账户 1:已绑定退货账户 + */ + private Byte bindStatus; + + public ChannelRefundLimit(Boolean isPlatAccount, Boolean isDefaultAccount,byte bindStatus) { + this.isPlatAccount = isPlatAccount; + this.isDefaultAccount = isDefaultAccount; + this.bindStatus = bindStatus; + } + + public ChannelRefundLimit(Boolean isPlatAccount, Boolean isDefaultAccount) { + this(isPlatAccount,isDefaultAccount,SUCCESS); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRetMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRetMsg.java new file mode 100644 index 0000000..5ffb765 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelRetMsg.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; + +import java.io.Serializable; + +/* +* 上游渠道侧响应信息包装类 +* +* @author terrfly +* +* @date 2021/6/8 17:31 +*/ +@Slf4j +@Data +@Accessors(chain = true) +public class ChannelRetMsg implements Serializable { + + /** 上游渠道返回状态 **/ + private ChannelState channelState; + + /** 渠道订单号 **/ + private String channelOrderId; + + /** 支付凭证上交易单号(微信、支付宝等交易单号) */ + private String platformOrderNo; + + /** 支付凭证上商户单号(微信、支付宝等商户单号) */ + private String platformMchOrderNo; + + /** 渠道用户标识 **/ + private String channelUserId; + + /** 渠道错误码 **/ + private String channelErrCode; + + /** 渠道错误描述 **/ + private String channelErrMsg; + + /** 渠道支付数据包, 一般用于支付订单的继续支付操作 **/ + private String channelAttach; + + /** 上游渠道返回的原始报文, 一般用于[运营平台的查询上游结果]功能 **/ + private String channelOriginResponse; + + /** 是否需要轮询查单(比如微信条码支付) 默认不查询订单 **/ + private boolean isNeedQuery = false; + + /** 响应结果(一般用于回调接口返回给上游数据 ) **/ + private ResponseEntity responseEntity; + + /** 渠道特殊数据,渠道自处理 **/ + private JSONObject channelBizData; + + /** + * 卡类型 参考Cs里面的 + */ + private String drType; + + private String wayCodeType; + + private ChannelJsapiMsg jsapiMsg; + + private ChannelAppletPayMsg liteMsg; + + //渠道状态枚举值 + public enum ChannelState { + CONFIRM_SUCCESS, //接口正确返回: 业务状态已经明确成功 + CONFIRM_FAIL, //接口正确返回: 业务状态已经明确失败 + WAITING, //接口正确返回: 上游处理中, 需通过定时查询/回调进行下一步处理 + UNKNOWN, //接口超时,或网络异常等请求, 或者返回结果的签名失败: 状态不明确 ( 上游接口变更, 暂时无法确定状态值 ) + API_RET_ERROR, //渠道侧出现异常( 接口返回了异常状态 ) + SYS_ERROR //本系统出现不可预知的异常 + } + + //静态初始函数 + public ChannelRetMsg(){} + public ChannelRetMsg(ChannelState channelState, String channelOrderId, String channelErrCode, String channelErrMsg) { + this.channelState = channelState; + this.channelOrderId = channelOrderId; + this.channelErrCode = channelErrCode; + this.channelErrMsg = channelErrMsg; + } + + /** 明确成功 **/ + public static ChannelRetMsg confirmSuccess(String channelOrderId){ + return new ChannelRetMsg(ChannelState.CONFIRM_SUCCESS, channelOrderId, null, null); + } + + /** 明确成功,附加扫码POS订单号 **/ + public static ChannelRetMsg confirmSuccess(String channelOrderId, String platformOrderNo, String platformMchOrderNo,String drType){ + ChannelRetMsg channelRetMsg = confirmSuccess(channelOrderId); + channelRetMsg.setPlatformOrderNo(platformOrderNo); + channelRetMsg.setPlatformMchOrderNo(platformMchOrderNo); + channelRetMsg.setDrType(drType); + return channelRetMsg; + } + + /** 明确失败 **/ + public static ChannelRetMsg confirmFail(String channelOrderId, String channelErrCode, String channelErrMsg){ + return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, channelOrderId, channelErrCode, channelErrMsg); + } + + /** 明确失败 **/ + public static ChannelRetMsg confirmFail(String channelErrCode, String channelErrMsg){ + return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, null, channelErrCode, channelErrMsg); + } + + /** 明确失败 **/ + public static ChannelRetMsg confirmFail(String channelOrderId){ + return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, channelOrderId, null, null); + } + + /** 明确失败 **/ + public static ChannelRetMsg confirmFail(){ + return new ChannelRetMsg(ChannelState.CONFIRM_FAIL, null, null, null); + } + + /** 处理中 **/ + public static ChannelRetMsg waiting(){ + return new ChannelRetMsg(ChannelState.WAITING, null, null, null); + } + + /** 异常的情况 **/ + public static ChannelRetMsg sysError(String channelErrMsg){ + return new ChannelRetMsg(ChannelState.SYS_ERROR, null, null, "系统:" + channelErrMsg); + } + + /** 状态未知的情况 **/ + public static ChannelRetMsg unknown(){ + return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, null); + } + + /** 状态未知的情况 **/ + public static ChannelRetMsg unknown(String channelErrMsg){ + return new ChannelRetMsg(ChannelState.UNKNOWN, null, null, channelErrMsg); + } + +} + + + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelUserInfoMsg.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelUserInfoMsg.java new file mode 100644 index 0000000..b97d866 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/ChannelUserInfoMsg.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; + +/* +* 渠道用户ID信息包装类 +* +* @author terrfly +* +* @date 2022/10/11 15:31 +*/ +@Slf4j +@Data +@Accessors(chain = true) +@AllArgsConstructor +public class ChannelUserInfoMsg implements Serializable { + + /** 获取用户ID的授权地址 **/ + private String redirectUrl; + + /** 渠道的唯一获取用户信息标识, 微信: 公众号appId, 支付宝为固定2088开头的appId **/ + private String channelAppId; + + /** 生成 **/ + public static ChannelUserInfoMsg gen(String redirectUrl, String channelAppId){ + return new ChannelUserInfoMsg(redirectUrl, channelAppId); + } + +} + + + + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/DivisionChannelNotifyModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/DivisionChannelNotifyModel.java new file mode 100644 index 0000000..10df23d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/msg/DivisionChannelNotifyModel.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.rqrs.msg; + +import lombok.Data; +import org.springframework.http.ResponseEntity; + +import java.util.Map; + +/*** +* 封装响应结果的数据 + * 直接写: MutablePair> 太过复杂! +* +* @author terrfly +* +* @date 2023/3/29 15:50 +*/ +@Data +public class DivisionChannelNotifyModel { + + /** 响应接口返回的数据 **/ + private ResponseEntity apiRes; + + /** 每一条记录的更新状态 **/ + private Map recordResultMap; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRQ.java new file mode 100644 index 0000000..92e9890 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +/* + * 关闭订单 请求参数对象 + * + * @author xiaoyu + * + * @date 2022/1/25 9:16 + */ +@Data +public class ClosePayOrderRQ extends AbstractMchAppRQ { + + /** 商户订单号 **/ + private String mchOrderNo; + + /** 支付系统订单号 **/ + private String payOrderId; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_PAY_ORDER_CLOSE; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRS.java new file mode 100644 index 0000000..2343610 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/ClosePayOrderRS.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.Data; + +/* + * 关闭订单 响应参数 + * + * @author xiaoyu + * + * @date 2022/1/25 9:17 + */ +@Data +public class ClosePayOrderRS extends AbstractRS { + + /** 上游渠道返回数据包 (无需JSON序列化) **/ + @JSONField(serialize = false) + private ChannelRetMsg channelRetMsg; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRQ.java new file mode 100644 index 0000000..7ffb961 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRQ.java @@ -0,0 +1,18 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import lombok.Data; + +/* +* 通用支付数据RQ +* +* @author terrfly +* +* @date 2021/6/8 17:31 +*/ +@Data +public class CommonPayDataRQ extends UnifiedOrderRQ { + + /** 请求参数: 支付数据包类型 **/ + private String payDataType; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRS.java new file mode 100644 index 0000000..52c3fe2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/CommonPayDataRS.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* +* 通用支付数据RS +* 根据set的值,响应不同的payDataType +* +* @author terrfly +* +* @date 2021/6/8 17:32 +*/ +@Data +public class CommonPayDataRS extends UnifiedOrderRS { + + /** 跳转地址 **/ + private String payUrl; + + /** 二维码地址 **/ + private String codeUrl; + + /** 二维码图片地址 **/ + private String codeImgUrl; + + /** 表单内容 **/ + private String formContent; + + @Override + public String buildPayDataType(){ + + if(StringUtils.isNotEmpty(payUrl)){ + return CS.PAY_DATA_TYPE.PAY_URL; + } + + if(StringUtils.isNotEmpty(codeUrl)){ + return CS.PAY_DATA_TYPE.CODE_URL; + } + + if(StringUtils.isNotEmpty(codeImgUrl)){ + return CS.PAY_DATA_TYPE.CODE_IMG_URL; + } + + if(StringUtils.isNotEmpty(formContent)){ + return CS.PAY_DATA_TYPE.FORM; + } + + return CS.PAY_DATA_TYPE.PAY_URL; + } + + @Override + public String buildPayData(){ + + if(StringUtils.isNotEmpty(payUrl)){ + return payUrl; + } + + if(StringUtils.isNotEmpty(codeUrl)){ + return codeUrl; + } + + if(StringUtils.isNotEmpty(codeImgUrl)){ + return codeImgUrl; + } + + if(StringUtils.isNotEmpty(formContent)){ + return formContent; + } + + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRQ.java new file mode 100644 index 0000000..77097da --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +/* +* 查询订单请求参数对象 +* +* @author terrfly +* +* @date 2021/6/8 17:40 +*/ +@Data +public class QueryPayOrderRQ extends AbstractMchAppRQ { + + /** 商户订单号 **/ + private String mchOrderNo; + + /** 支付系统订单号 **/ + private String payOrderId; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_PAY_ORDER_QUERY; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRS.java new file mode 100644 index 0000000..05941c2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/QueryPayOrderRS.java @@ -0,0 +1,212 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +import java.util.HashSet; +import java.util.Set; + +/* +* 查询订单 响应参数 +* +* @author terrfly +* +* @date 2021/6/8 17:40 +*/ +@Data +public class QueryPayOrderRS extends AbstractRS { + + public static final Set EXT_PRAMS = new HashSet<>(); + static{ + EXT_PRAMS.add("storeId"); EXT_PRAMS.add("lng"); EXT_PRAMS.add("lat"); + EXT_PRAMS.add("qrcId"); EXT_PRAMS.add("wayCodeType"); EXT_PRAMS.add("mchFeeRate"); + EXT_PRAMS.add("mchFeeAmount"); EXT_PRAMS.add("channelUser"); EXT_PRAMS.add("divisionMode"); + EXT_PRAMS.add("buyerRemark"); EXT_PRAMS.add("sellerRemark");EXT_PRAMS.add("expiredTime"); + EXT_PRAMS.add("platformOrderNo");EXT_PRAMS.add("platformMchOrderNo"); + } + + + /** + * 支付订单号 + */ + private String payOrderId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 商户应用ID + */ + private String appId; + + /** + * 商户订单号 + */ + private String mchOrderNo; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 支付方式代码 + */ + private String wayCode; + + /** + * 支付金额,单位分 + */ + private Long amount; + + /** + * 三位货币代码,人民币:cny + */ + private String currency; + + /** + * 支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte state; + + /** + * 客户端IP + */ + private String clientIp; + + /** + * 商品标题 + */ + private String subject; + + /** + * 商品描述信息 + */ + private String body; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 渠道支付错误码 + */ + private String errCode; + + /** + * 渠道支付错误描述 + */ + private String errMsg; + + /** + * 商户扩展参数 + */ + private String extParam; + + /** + * 订单支付成功时间 + */ + private Long successTime; + + /** + * 创建时间 + */ + private Long createdAt; + + + /////////// 以下为扩展参数 //////////////////////// + + + /** + * 商户门店ID + */ + private String storeId; + + /** + * 经度 + */ + private String lng; + + /** + * 纬度 + */ + private String lat; + + /** + * 码牌ID + */ + private Long qrcId; + + /** + * 支付方式代码分类 + */ + private String wayCodeType; + + /** + * 商户手续费费率快照 + */ + private String mchFeeRate; + + /** + * 商户实际手续费,单位分 ( 订单手续费 - 手续费退还金额 ) + */ + private Long mchFeeAmount; + + /** + * 渠道用户标识,如微信openId,支付宝账号 + */ + private String channelUser; + + /** + * 订单分账模式:0-该笔订单不允许分账, 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额) + */ + private Byte divisionMode; + + /** + * 买家备注 + */ + private String buyerRemark; + + /** + * 卖家备注 + */ + private String sellerRemark; + + /** + * 订单失效时间 + */ + private Long expiredTime; + + /** + * 支付凭证交易单号 + */ + private String platformOrderNo; + + /** + * 支付凭证商户单号 + */ + private String platformMchOrderNo; + + + public static QueryPayOrderRS buildByPayOrder(PayOrder payOrder){ + + if(payOrder == null){ + return null; + } + + QueryPayOrderRS result = new QueryPayOrderRS(); + BeanUtils.copyProperties(payOrder, result); + result.setSuccessTime(payOrder.getSuccessTime() == null ? null : payOrder.getSuccessTime().getTime()); + result.setCreatedAt(payOrder.getCreatedAt() == null ? null : payOrder.getCreatedAt().getTime()); + result.setExpiredTime(payOrder.getExpiredTime() == null ? null : payOrder.getExpiredTime().getTime()); + + return result; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRQ.java new file mode 100644 index 0000000..430b958 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRQ.java @@ -0,0 +1,339 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.payway.*; +import lombok.Data; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.validator.constraints.Range; +import org.springframework.beans.BeanUtils; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/* +* 创建订单请求参数对象 +* 聚合支付接口(统一下单) +* +* @author terrfly +* +* @date 2021/6/8 17:33 +*/ +@Data +@Accessors(chain = true) +public class UnifiedOrderRQ extends AbstractMchAppRQ { + + public static final Integer DEFAULT_LIMIT_PAY = -1; + + /** 商户订单号 **/ + @NotBlank(message="商户订单号不能为空") + private String mchOrderNo; + + /** 支付方式 如: wxpay_jsapi,alipay_wap等 **/ + @NotBlank(message="支付方式不能为空") + private String wayCode; + + /** 支付金额, 单位:分 **/ + @NotNull(message="支付金额不能为空") + @Min(value = 1, message = "支付金额不能为空") + private Long amount; + + /** 货币代码 **/ + @NotBlank(message="货币代码不能为空") + private String currency; + + /** 客户端IP地址 **/ + private String clientIp; + + /** 商品标题 **/ + @NotBlank(message="商品标题不能为空") + private String subject; + + /** 商品描述信息 **/ + @NotBlank(message="商品描述信息不能为空") + private String body; + + /** 商户的门店ID **/ + private String storeId; + + /** 门店收银员ID **/ + private Long storeUserId; + + /** 设备信息 **/ + private String deviceInfo; + + /** 商户的码牌ID **/ + private Long qrcId; + + /** 异步通知地址 **/ + private String notifyUrl; + + /** 跳转通知地址 **/ + private String returnUrl; + + /** 卖家备注 **/ + private String sellerRemark; + + /** 买家备注 **/ + private String buyerRemark; + + /** 订单失效时间, 单位:秒 **/ + private Integer expiredTime; + + /** 终端编号(商户自行录入的 trmNo 字段 ) **/ + private String mchTrmNo; + + /** 特定渠道发起额外参数 **/ + private String channelExtra; + + /** 商户扩展参数 **/ + private String extParam; + + /** 分账模式: 0-该笔订单不允许分账, 1-支付成功按配置自动完成分账, 2-商户手动分账(解冻商户金额) **/ + @Range(min = 0, max = 2, message = "分账模式设置值有误") + private Byte divisionMode; + + /** 渠道特殊业务数据 **/ + private String channelBizData; + + /** 会员ID **/ + private String mbrId; + + /** 会员手机号 **/ + private String mbrTel; + + /** + * 是否禁用信用卡 -1:不禁用 1:禁用 不传标识不禁用 + */ + private Integer limitPay; + + /** + * 暂时只支持扫码支付 + * 扫码类型 0或不填:扫码支付 1:支付宝刷脸支付;2: 微信刷脸支付 + */ + private Integer scanType; + + /** + * 花呗分期参数 取值 3 6 12 期 + */ + private Integer hbFqNum; + + /** + * 卖家承担手续费比例 支付宝花呗分期必送字段: 卖家承担手续费比例,间连模式下只支持传0。 + */ + private Integer hbFqPercent; + + /** + * 优惠对象 + */ + private JSONObject discount; + + /** + * 红包营销规则 + */ + private Boolean isMarketRed; + + /** + * 是否校验小程序参数 + */ + @JSONField(serialize = false) + private Boolean isAppletCheck = false; + + /** + * 是否请求渠道 + */ + @JSONField(serialize = false) + private Boolean isReqChannel = true; + + /** + * 是否来源路由 + */ + @JSONField(serialize = false) + private Boolean isRoute = false; + + @JSONField(serialize = false) + private String tk; + + /** + * 路由编号 + */ + @JSONField(serialize = false) + private String routeNo; + + + + /** 返回真实的bizRQ **/ + public UnifiedOrderRQ buildBizRQ(){ + if(CS.PAY_WAY_CODE.ALI_BAR.equals(wayCode)){ + AliBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_JSAPI.equals(wayCode)){ + AliJsapiOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliJsapiOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_LITE.equals(wayCode)){ + AliLiteOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliLiteOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.QR_CASHIER.equals(wayCode)){ + this.isReqChannel = false; + QrCashierOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), QrCashierOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WEB_CASHIER.equals(wayCode)){ + this.isReqChannel = false; + WebCashierOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WebCashierOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_JSAPI.equals(wayCode)){ + WxJsapiOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxJsapiOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_APP.equals(wayCode)){ + WxAppOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxAppOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_LITE.equals(wayCode)){ + WxLiteOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxLiteOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_BAR.equals(wayCode)){ + WxBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_NATIVE.equals(wayCode)){ + WxNativeOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxNativeOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.WX_H5.equals(wayCode)){ + WxH5OrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), WxH5OrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.YSF_BAR.equals(wayCode)){ + YsfBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), YsfBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.YSF_JSAPI.equals(wayCode)){ + this.isReqChannel = true; + YsfJsapiOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), YsfJsapiOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.AUTO_BAR.equals(wayCode)){ + AutoBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AutoBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_APP.equals(wayCode)){ + AliAppOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliAppOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_WAP.equals(wayCode)){ + AliWapOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliWapOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_PC.equals(wayCode)){ + this.isReqChannel = true; + AliPcOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliPcOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.ALI_QR.equals(wayCode)){ + AliQrOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), AliQrOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_APP.equals(wayCode)){ + UpAppOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpAppOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_WAP.equals(wayCode)){ + UpWapOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpWapOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_QR.equals(wayCode)){ + UpQrOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpQrOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_BAR.equals(wayCode)){ + UpBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_B2B.equals(wayCode)){ + UpB2bOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpB2bOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.UP_PC.equals(wayCode)){ + UpPcOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), UpPcOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if (CS.PAY_WAY_CODE.PP_PC.equals(wayCode)){ + PPPcOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), PPPcOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.SAND_H5.equals(wayCode)){ + SandH5OrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), SandH5OrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.AUTO_POS.equals(wayCode)){ + AutoPosOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelBizData, "{}"), AutoPosOrderRQ.class); + + AutoPosOrderRQ autoPosOrderRQ = AutoPosOrderRQ.getDefaultAutoPosOrderRQ(); + BeanUtil.copyProperties(bizRQ, autoPosOrderRQ, CopyOptions.create().setIgnoreNullValue(true)); + + BeanUtils.copyProperties(this, autoPosOrderRQ); + return autoPosOrderRQ; + }else if(CS.PAY_WAY_CODE.CASHIER.equals(wayCode)){ + ChannelCashierOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), ChannelCashierOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.BANK_QUICK.equals(wayCode)){ + BankQuickOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), BankQuickOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.BANK_B2C.equals(wayCode)){ + BankB2cOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), BankB2cOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.DCEP_BAR.equals(wayCode)){ + DcepBarOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), DcepBarOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + }else if(CS.PAY_WAY_CODE.DCEP_QR.equals(wayCode)){ + DcepQrOrderRQ bizRQ = JSONObject.parseObject(StringUtils.defaultIfEmpty(this.channelExtra, "{}"), DcepQrOrderRQ.class); + BeanUtils.copyProperties(this, bizRQ); + return bizRQ; + } + + return this; + } + + /** 获取渠道用户ID **/ + @JSONField(serialize = false) + public String getChannelUserId(){ + return null; + } + + + @Data + public static class DeviceInfo { + + /** 设备类型:qr_code-码牌,qr_box_kxp 扫码客显屏音箱 scan_pos-扫码POS,auto_pos-智能POS,other-其他 **/ + private String deviceType; + + /** 设备号 **/ + private String deviceNo; + + /** 设备厂商 (智能POS厂商即为 ifCode,扫码POS仅商户系统调用,已通过cahnnelBizData传值) **/ + private String provider; + + } + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_PAY_ORDER; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRS.java new file mode 100644 index 0000000..3ec1442 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/UnifiedOrderRS.java @@ -0,0 +1,80 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelAppletPayMsg; +import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg; +import lombok.Data; +import lombok.NoArgsConstructor; + +/* +* 创建订单(统一订单) 响应参数 +* +* @author terrfly +* +* @date 2021/6/8 17:34 +*/ +@Data +@NoArgsConstructor +public class UnifiedOrderRS extends AbstractRS { + + /** 支付订单号 **/ + private String payOrderId; + + /** 商户订单号 **/ + private String mchOrderNo; + + /** 订单状态 **/ + private Byte orderState; + + /** 支付参数类型 ( 无参数, 调起支付插件参数, 重定向到指定地址, 用户扫码 ) **/ + private String payDataType; + + /** 支付参数 **/ + private String payData; + + /** 渠道返回错误代码 **/ + private String errCode; + + /** 渠道返回错误信息 **/ + private String errMsg; + + /** 订单信息, 当直接支付成功时会返回此数据。 **/ + private String payOrderInfo; + + /** 上游渠道返回数据包 (无需JSON序列化) **/ + @JSONField(serialize = false) + private ChannelRetMsg channelRetMsg; + + /** + * 扩展参数 + */ + private JSONObject extData; + + /** + * 门店名称 + */ + private String storeName; + + + + /** 生成聚合支付参数 (仅统一下单接口使用) **/ + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + /** 生成支付参数 **/ + public String buildPayData(){ + return ""; + } + + public UnifiedOrderRS(String payOrderId, String payUrl, ChannelAppletPayMsg payMsg) { + this.payOrderId = payOrderId; + this.payData = payUrl; + ChannelRetMsg retMsg = ChannelRetMsg.waiting(); + retMsg.setLiteMsg(payMsg); + this.setChannelRetMsg(retMsg); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRQ.java new file mode 100644 index 0000000..9749cd4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRQ.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* +* 支付方式: ALI_APP +* +* @author terrfly +* +* @date 2021/6/8 17:34 +*/ +@Data +public class AliAppOrderRQ extends UnifiedOrderRQ { + + /** 支付宝用户ID **/ + @NotBlank(message = "用户ID不能为空") + private String buyerUserId; + + /** 构造函数 **/ + public AliAppOrderRQ(){ + this.setWayCode(CS.PAY_DATA_TYPE.ALI_APP); //默认 wayCode, 避免validate出现问题 + } + + + @Override + public String getChannelUserId(){ + return this.buyerUserId; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRS.java new file mode 100644 index 0000000..f9c1c6d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliAppOrderRS.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: ALI_APP + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliAppOrderRS extends UnifiedOrderRS { + + private String payData; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.ALI_APP; + } + + @Override + public String buildPayData(){ + return payData; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRQ.java new file mode 100644 index 0000000..eb93aee --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRQ.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: ALI_BAR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliBarOrderRQ extends UnifiedOrderRQ { + + public final Integer DEF_SCAN_TYPE = 0; + + /** 用户 支付条码 **/ + @NotBlank(message = "支付条码不能为空") + private String authCode; + + /** 构造函数 **/ + public AliBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_BAR); //默认 ali_bar, 避免validate出现问题 + } + +// @Override +// public Integer getScanType() { +// if(this.getScanType() == null){ +// return DEF_SCAN_TYPE; +// }else{ +// return super.getScanType(); +// } +// } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRS.java new file mode 100644 index 0000000..9229141 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliBarOrderRS.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: ALI_BAR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliBarOrderRS extends UnifiedOrderRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + @Override + public String buildPayData(){ + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRQ.java new file mode 100644 index 0000000..7516973 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRQ.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: ALI_JSAPI + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliJsapiOrderRQ extends UnifiedOrderRQ { + + /** 支付宝用户ID **/ + @NotBlank(message = "用户ID不能为空") + private String buyerUserId; + + /** 传入该appId下单上送至三方 **/ + private String subAppId; + + /** 构造函数 **/ + public AliJsapiOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_JSAPI); + } + + @Override + public String getChannelUserId(){ + return this.buyerUserId; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRS.java new file mode 100644 index 0000000..e97b1eb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliJsapiOrderRS.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.Data; + +/* + * 支付方式: ALI_JSAPI + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliJsapiOrderRS extends UnifiedOrderRS { + + /** 调起支付插件的支付宝订单号 **/ + private String alipayTradeNo; + + /** + * 花呗分期参数 取值 3 6 12 期 + */ + private Integer hbFqNum; + + /** + * 卖家承担手续费比例 支付宝花呗分期必送字段: 卖家承担手续费比例,间连模式下只支持传0。 + */ + private Integer hbFqPercent; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.ALI_APP; + } + + @Override + public String buildPayData(){ + return JsonKit.newJson("alipayTradeNo", alipayTradeNo).toString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRQ.java new file mode 100644 index 0000000..450bd96 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRQ.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: ALI_LITE + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliLiteOrderRQ extends UnifiedOrderRQ { + + /** 支付宝用户ID **/ + @NotBlank(message = "用户ID不能为空") + private String buyerUserId; + + /** 传入该appId下单上送至三方 **/ + private String subAppId; + + /** 构造函数 **/ + public AliLiteOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_LITE); + } + + @Override + public String getChannelUserId(){ + return this.buyerUserId; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRS.java new file mode 100644 index 0000000..ceb5591 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliLiteOrderRS.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.Data; + +/* + * 支付方式: ALI_LITE + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliLiteOrderRS extends UnifiedOrderRS { + + /** 调起支付插件的支付宝订单号 **/ + private String alipayTradeNo; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.ALI_APP; + } + + @Override + public String buildPayData(){ + return JsonKit.newJson("alipayTradeNo", alipayTradeNo).toString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRQ.java new file mode 100644 index 0000000..8a14b95 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: ALI_PC + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliPcOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public AliPcOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_PC); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRS.java new file mode 100644 index 0000000..eadc433 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliPcOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: ALI_PC + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliPcOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRQ.java new file mode 100644 index 0000000..3e54fdc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: ALI_QR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliQrOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public AliQrOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_QR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRS.java new file mode 100644 index 0000000..d0cea26 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliQrOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: ALI_QR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliQrOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRQ.java new file mode 100644 index 0000000..ad88f2a --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: ALI_WAP + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliWapOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public AliWapOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.ALI_WAP); //默认 ALI_WAP, 避免validate出现问题 + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRS.java new file mode 100644 index 0000000..8570812 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AliWapOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: ALI_WAP + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AliWapOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRQ.java new file mode 100644 index 0000000..2d2e5b4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRQ.java @@ -0,0 +1,25 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +/* + * 支付方式: AUTO_BAR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AutoBarOrderRQ extends UnifiedOrderRQ { + + /** 条码值 **/ + private String authCode; + + /** 构造函数 **/ + public AutoBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.AUTO_BAR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRS.java new file mode 100644 index 0000000..44f5afd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoBarOrderRS.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: AUTO_BAR + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AutoBarOrderRS extends UnifiedOrderRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + @Override + public String buildPayData(){ + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRQ.java new file mode 100644 index 0000000..ca61636 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRQ.java @@ -0,0 +1,39 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +/* + * 支付方式: AUTO_POS + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AutoPosOrderRQ extends UnifiedOrderRQ { + + /** 支付渠道,银行卡:CARD, 扫一扫:SCAN, 付款码:QRCODE **/ + private String channelType; + + /** 支付方式,参考CS.PAY_WAY_CODE_TYPE **/ + private String payType; + + /** 构造函数 **/ + public AutoPosOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.AUTO_POS); + } + + /** 构造函数 **/ + public AutoPosOrderRQ(String channelType, String payType) { + this.channelType = channelType; + this.payType = payType; + } + + /** 构造函数 **/ + public static AutoPosOrderRQ getDefaultAutoPosOrderRQ(){ + return new AutoPosOrderRQ("CARD", "UNIONPAY"); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRS.java new file mode 100644 index 0000000..06ce8a8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/AutoPosOrderRS.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: QR_CASHIER + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class AutoPosOrderRS extends CommonPayDataRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRQ.java new file mode 100644 index 0000000..cc85921 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: BANK_B2C + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class BankB2cOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public BankB2cOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.BANK_B2C); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRS.java new file mode 100644 index 0000000..c5a0cd1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankB2cOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: BANK_B2C + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class BankB2cOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRQ.java new file mode 100644 index 0000000..964a419 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: BANK_QUICK + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class BankQuickOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public BankQuickOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.BANK_QUICK); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRS.java new file mode 100644 index 0000000..925f67b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/BankQuickOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: BANK_QUICK + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class BankQuickOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRQ.java new file mode 100644 index 0000000..7dacaf7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRQ.java @@ -0,0 +1,55 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.openapi.ParamException; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 支付方式: SAND_H5 + * + * @author jmdhappy + * + * @date 2021/12/31 12:34 + */ +@Data +public class ChannelCashierOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public ChannelCashierOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.CASHIER); + } + + public UnifiedOrderRQ preCheck() { + if (StringUtils.isEmpty(this.getCurrency())) { + throw new ParamException("货币类型[currency]参数不能为空"); + } + if (StringUtils.isEmpty(this.getMchOrderNo())) { + throw new ParamException("商户请求流水号[mchOrderNo]参数不能为空"); + } + if (this.getAmount() == null || this.getAmount() < 0) { + throw new ParamException("交易金额[amount]参数不能为空或参数格式不合法"); + } + if (this.getMchOrderNo().length() > 32) { + throw new ParamException("商户请求流水号[mchOrderNo]长度不允许超过32位"); + } + if (StringUtils.isEmpty(this.getSubject())) { + throw new ParamException("订单标题[subject]参数不能为空"); + } + if (StringUtils.isEmpty(this.getStoreId())) { + throw new ParamException("门店ID[storeId]参数不能为空"); + } + if (this.getExpiredTime() != null && (this.getExpiredTime() < 5 || this.getExpiredTime() > 1440)) { + throw new ParamException("订单过期时间[expiredTime]参数需要介于5-1440分钟之间"); + } + if (StringUtils.isEmpty(this.getClientIp())) { + throw new ParamException("付款方客户端ip[clientIp]参数不能为空"); + } + if (this.getLimitPay() == null) { + this.setLimitPay(-1); + } + return this; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRS.java new file mode 100644 index 0000000..f81a349 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/ChannelCashierOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: SAND_H5 + * + * @author jmdhappy + * + * @date 2021/12/31 12:34 + */ +@Data +public class ChannelCashierOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRQ.java new file mode 100644 index 0000000..4674897 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: DCEP_BAR + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class DcepBarOrderRQ extends UnifiedOrderRQ { + + /** 用户 支付条码 **/ + @NotBlank(message = "支付条码不能为空") + private String authCode; + + /** 构造函数 **/ + public DcepBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.DCEP_BAR); //默认 wx_bar, 避免validate出现问题 + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRS.java new file mode 100644 index 0000000..5e133fb --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepBarOrderRS.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: WX_BAR + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class DcepBarOrderRS extends UnifiedOrderRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + @Override + public String buildPayData(){ + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRQ.java new file mode 100644 index 0000000..177026d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: DCEP_QR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class DcepQrOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public DcepQrOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.DCEP_QR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRS.java new file mode 100644 index 0000000..7a03460 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/DcepQrOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: DCEP_QR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class DcepQrOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/KqH5OrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/KqH5OrderRQ.java new file mode 100644 index 0000000..2f136da --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/KqH5OrderRQ.java @@ -0,0 +1,23 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: KQ_H5 + * + * @author crystal + * @site + * @date + */ +@Data +public class KqH5OrderRQ extends CommonPayDataRQ { + + + /** 构造函数 **/ + public KqH5OrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.KQ_H5); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRQ.java new file mode 100644 index 0000000..91575f3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * none. + * + * @author 陈泉 + * @package com.jeequan.jeepay.pay.rqrs.payorder.payway + * @create 2021/11/15 17:52 + */ +@Data +public class PPPcOrderRQ extends CommonPayDataRQ { + + /** + * 商品描述信息 + **/ + @NotBlank(message = "取消支付返回站点") + private String cancelUrl; + + public PPPcOrderRQ() { + this.setWayCode(CS.PAY_WAY_CODE.PP_PC); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRS.java new file mode 100644 index 0000000..0b93649 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/PPPcOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/** + * none. + * + * @author 陈泉 + * @package com.jeequan.jeepay.pay.rqrs.payorder.payway + * @create 2021/11/15 19:56 + */ +@Data +public class PPPcOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRQ.java new file mode 100644 index 0000000..d9fce47 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRQ.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: QR_CASHIER + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class QrCashierOrderRQ extends CommonPayDataRQ { + + /** 聚合码入口类型: h5 lite **/ + private String entryPageType; + + /** 进入小程序支付入口类型: wxapp aliapp wxh5 alih5 **/ + private String entryLiteType; + + /** 构造函数 **/ + public QrCashierOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.QR_CASHIER); + } + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRS.java new file mode 100644 index 0000000..53bdaa6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/QrCashierOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: QR_CASHIER + * + * @author terrfly + * + * @date 2021/6/8 17:34 + */ +@Data +public class QrCashierOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRQ.java new file mode 100644 index 0000000..b2e0724 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRQ.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: SAND_H5 + * + * @author jmdhappy + * + * @date 2021/12/31 12:34 + */ +@Data +public class SandH5OrderRQ extends CommonPayDataRQ { + + /** 产品编码 **/ + private String productCode; + + /** 支付扩展域,参考杉德文档:https://www.yuque.com/docs/share/e098fee0-0830-4555-ba92-56d2ea0bce73#TlPj7 **/ + private String payExtra; + + /** 终端/网站参数,参考杉德文档:https://www.yuque.com/docs/share/e098fee0-0830-4555-ba92-56d2ea0bce73#TlPj7 **/ + private String metaOption; + + /** 构造函数 **/ + public SandH5OrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.SAND_H5); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRS.java new file mode 100644 index 0000000..f214f2f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/SandH5OrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: SAND_H5 + * + * @author jmdhappy + * + * @date 2021/12/31 12:34 + */ +@Data +public class SandH5OrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRQ.java new file mode 100644 index 0000000..ddbf414 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: UPACP_APP + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpAppOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public UpAppOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_APP); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRS.java new file mode 100644 index 0000000..4e3edf6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpAppOrderRS.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_APP + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpAppOrderRS extends CommonPayDataRS { + + private String payData; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.YSF_APP; + } + + @Override + public String buildPayData(){ + return payData; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRQ.java new file mode 100644 index 0000000..219be4c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: UPACP_B2B + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpB2bOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public UpB2bOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_B2B); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRS.java new file mode 100644 index 0000000..907c0b4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpB2bOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_B2B + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpB2bOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRQ.java new file mode 100644 index 0000000..38c70d3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: UPACP_BAR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpBarOrderRQ extends CommonPayDataRQ { + + /** 用户 支付条码 **/ + @NotBlank(message = "支付条码不能为空") + private String authCode; + + /** 构造函数 **/ + public UpBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_BAR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRS.java new file mode 100644 index 0000000..42a0fec --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpBarOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_BAR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpBarOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRQ.java new file mode 100644 index 0000000..002fae7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRQ.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: UP_JSAPI + * + * @author jmdhappy + * + * @date 2021/6/8 17:34 + */ +@Data +public class UpJsapiOrderRQ extends UnifiedOrderRQ { + + /** 支付宝用户ID **/ + @NotBlank(message = "用户ID不能为空") + private String userId; + + /** 构造函数 **/ + public UpJsapiOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_JSAPI); + } + + @Override + public String getChannelUserId(){ + return this.userId; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRS.java new file mode 100644 index 0000000..15af96b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpJsapiOrderRS.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.Data; + +/* + * 支付方式: UP_JSAPI + * + * @author jmdhappy + * + * @date 2022/3/17 12:34 + */ +@Data +public class UpJsapiOrderRS extends UnifiedOrderRS { + + /** 调起支付插件的云闪付订单号 **/ + private String redirectUrl; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.YSF_APP; + } + + @Override + public String buildPayData(){ + return JsonKit.newJson("redirectUrl", redirectUrl).toString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRQ.java new file mode 100644 index 0000000..e5b8aea --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: UPACP_PC + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpPcOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public UpPcOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_PC); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRS.java new file mode 100644 index 0000000..31cc2d6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpPcOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_PC + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpPcOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRQ.java new file mode 100644 index 0000000..8187b4d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: UPACP_QR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpQrOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public UpQrOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_QR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRS.java new file mode 100644 index 0000000..e9da68c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpQrOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_QR + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpQrOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRQ.java new file mode 100644 index 0000000..e54701d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: UPACP_WAP + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpWapOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public UpWapOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.UP_WAP); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRS.java new file mode 100644 index 0000000..f7199f3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/UpWapOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: UPACP_WAP + * + * @author jmdhappy + * + * @date 2021/12/1 19:57 + */ +@Data +public class UpWapOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRQ.java new file mode 100644 index 0000000..24dfcae --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRQ.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: WEB_CASHIER (统一收银台) + * + * @author terrfly + * + * @date 2022/6/28 17:34 + */ +@Data +public class WebCashierOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public WebCashierOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.WEB_CASHIER); + } + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRS.java new file mode 100644 index 0000000..e56f21c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WebCashierOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: WEB_CASHIER + * + * @author terrfly + * + * @date 2022/6/28 17:34 + */ +@Data +public class WebCashierOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRQ.java new file mode 100644 index 0000000..3498b98 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRQ.java @@ -0,0 +1,33 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: WX_APP + * + * @author xiaoyu + * + * @date 2022/12/20 8:12 + */ +@Data +public class WxAppOrderRQ extends UnifiedOrderRQ { + + /** 微信openid **/ + @NotBlank(message = "openid不能为空") + private String openid; + + /** 构造函数 **/ + public WxAppOrderRQ(){ + this.setWayCode(CS.PAY_DATA_TYPE.WX_APP); //默认 wayCode, 避免validate出现问题 + } + + + @Override + public String getChannelUserId(){ + return this.openid; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRS.java new file mode 100644 index 0000000..8c294aa --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxAppOrderRS.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: WX_APP + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxAppOrderRS extends UnifiedOrderRS { + + /** 预支付数据包 **/ + private String payData; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.WX_APP; + } + + @Override + public String buildPayData(){ + return payData; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRQ.java new file mode 100644 index 0000000..8765599 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRQ.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: WX_BAR + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxBarOrderRQ extends UnifiedOrderRQ { + + /** 用户 支付条码 **/ + @NotBlank(message = "支付条码不能为空") + private String authCode; + + private String subAppid; + + /** 构造函数 **/ + public WxBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.WX_BAR); //默认 wx_bar, 避免validate出现问题 + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRS.java new file mode 100644 index 0000000..825f5fc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxBarOrderRS.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: WX_BAR + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxBarOrderRS extends UnifiedOrderRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + @Override + public String buildPayData(){ + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRQ.java new file mode 100644 index 0000000..d923ffa --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: WX_H5 + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxH5OrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public WxH5OrderRQ() { + this.setWayCode(CS.PAY_WAY_CODE.WX_H5); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRS.java new file mode 100644 index 0000000..2d80689 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxH5OrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: WX_H5 + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxH5OrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRQ.java new file mode 100644 index 0000000..3c40056 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRQ.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: WX_JSAPI + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxJsapiOrderRQ extends UnifiedOrderRQ { + + /** 微信openid **/ + @NotBlank(message = "openid不能为空") + private String openid; + + /** 标志是否为 subMchAppId的对应 openId, 0-否, 1-是, 默认否 **/ + private Byte isSubOpenId; + + /** 微信appId 需先在三方渠道配置;传入该appId下单上送至三方 **/ + private String subAppid; + + /** 构造函数 **/ + public WxJsapiOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.WX_JSAPI); + } + + @Override + public String getChannelUserId() { + return this.openid; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRS.java new file mode 100644 index 0000000..2d86737 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxJsapiOrderRS.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/* + * 支付方式: WX_JSAPI + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxJsapiOrderRS extends UnifiedOrderRS { + + /** 预支付数据包 **/ + private String payInfo; + + /** 跳转支付地址 **/ + private String payUrl; + + @Override + public String buildPayDataType(){ + if (StringUtils.isNotEmpty(payUrl)) { + return CS.PAY_DATA_TYPE.PAY_URL; + } + return CS.PAY_DATA_TYPE.WX_APP; + } + + @Override + public String buildPayData(){ + if (StringUtils.isNotEmpty(payUrl)) { + return payUrl; + } + return payInfo; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRQ.java new file mode 100644 index 0000000..207c61e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRQ.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: WX_LITE + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxLiteOrderRQ extends UnifiedOrderRQ { + + /** 微信openid **/ + @NotBlank(message = "openid不能为空") + private String openid; + + /** 标志是否为 subMchLiteAppId的对应 openId, 0-否, 1-是, 默认否 **/ + private Byte isSubOpenId; + + /** 微信appId 需先在三方渠道配置;传入该appId下单上送至三方 **/ + private String subAppid; + + /** 构造函数 **/ + public WxLiteOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.WX_LITE); + } + + @Override + public String getChannelUserId() { + return this.openid; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRS.java new file mode 100644 index 0000000..8ddfc23 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxLiteOrderRS.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: WX_LITE + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxLiteOrderRS extends UnifiedOrderRS { + + /** 预支付数据包 **/ + private String payInfo; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.WX_APP; + } + + @Override + public String buildPayData(){ + return payInfo; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRQ.java new file mode 100644 index 0000000..760e4b6 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRQ.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRQ; +import lombok.Data; + +/* + * 支付方式: WX_NATIVE + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxNativeOrderRQ extends CommonPayDataRQ { + + /** 构造函数 **/ + public WxNativeOrderRQ() { + this.setWayCode(CS.PAY_WAY_CODE.WX_NATIVE); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRS.java new file mode 100644 index 0000000..ecf1f43 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/WxNativeOrderRS.java @@ -0,0 +1,16 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.model.rqrs.payorder.CommonPayDataRS; +import lombok.Data; + +/* + * 支付方式: WX_NATIVE + * + * @author zhuxiao + * + * @date 2021/6/8 17:34 + */ +@Data +public class WxNativeOrderRS extends CommonPayDataRS { + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRQ.java new file mode 100644 index 0000000..55ad8fe --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: YSF_BAR + * + * @author pangxiaoyu + * + * @date 2021/6/8 17:34 + */ +@Data +public class YsfBarOrderRQ extends UnifiedOrderRQ { + + /** 用户 支付条码 **/ + @NotBlank(message = "支付条码不能为空") + private String authCode; + + /** 构造函数 **/ + public YsfBarOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.YSF_BAR); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRS.java new file mode 100644 index 0000000..78ab543 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfBarOrderRS.java @@ -0,0 +1,27 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import lombok.Data; + +/* + * 支付方式: YSF_BAR + * + * @author pangxiaoyu + * + * @date 2021/6/8 17:34 + */ +@Data +public class YsfBarOrderRS extends UnifiedOrderRS { + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.NONE; + } + + @Override + public String buildPayData(){ + return ""; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRQ.java new file mode 100644 index 0000000..bffc47d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRQ.java @@ -0,0 +1,43 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* + * 支付方式: YSF_JSAPI + * + * @author pangxiaoyu + * + * @date 2021/6/8 17:34 + */ +@Data +public class YsfJsapiOrderRQ extends UnifiedOrderRQ { + + /** userId **/ + @NotBlank(message = "userId不能为空") + private String userId; + + /** + * 收款方向银联推送订单时上送的前台通知地址(仅允许为外网地址),用户完成支付点击,“返回”后,银联通过浏览器POST请求到该地址。 当transType为JSAPI,payMode为UQRCODEPAY时,可选填此字段 + */ + private String frontUrl; + + /** + * 收款方向银联推送订单时上送的前台通知地址(仅允许为外网地址),用户完成支付点击,“返回”后,银联通过浏览器POST请求到该地址。 当transType为JSAPI,payMode为UQRCODEPAY时,可选填此字段 + */ + private String frontFailUrl; + + /** 构造函数 **/ + public YsfJsapiOrderRQ(){ + this.setWayCode(CS.PAY_WAY_CODE.YSF_JSAPI); + } + + @Override + public String getChannelUserId() { + return this.userId; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRS.java new file mode 100644 index 0000000..92ee57e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/payorder/payway/YsfJsapiOrderRS.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.model.rqrs.payorder.payway; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.payorder.UnifiedOrderRS; +import com.jeequan.jeepay.core.utils.JsonKit; +import lombok.Data; + +/* + * 支付方式: YSF_JSAPI + * + * @author pangxiaoyu + * + * @date 2021/6/8 17:34 + */ +@Data +public class YsfJsapiOrderRS extends UnifiedOrderRS { + + /** 调起支付插件的云闪付订单号 **/ + private String redirectUrl; + + @Override + public String buildPayDataType(){ + return CS.PAY_DATA_TYPE.YSF_APP; + } + + @Override + public String buildPayData(){ + return JsonKit.newJson("redirectUrl", redirectUrl).toString(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRQ.java new file mode 100644 index 0000000..9b77f7b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.refund; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +/* +* 查询退款单请求参数对象 +* +* @author terrfly +* +* @date 2021/6/17 14:07 +*/ +@Data +public class QueryRefundOrderRQ extends AbstractMchAppRQ { + + /** 商户退款单号 **/ + private String mchRefundNo; + + /** 支付系统退款订单号 **/ + private String refundOrderId; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_REFUND_ORDER_QUERY; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRS.java new file mode 100644 index 0000000..a874296 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/QueryRefundOrderRS.java @@ -0,0 +1,108 @@ +package com.jeequan.jeepay.core.model.rqrs.refund; + +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +/* +* 查询退款单 响应参数 +* +* @author terrfly +* +* @date 2021/6/17 14:08 +*/ +@Data +public class QueryRefundOrderRS extends AbstractRS { + + /** + * 退款订单号(支付系统生成订单号) + */ + private String refundOrderId; + + /** + * 支付订单号(与t_pay_order对应) + */ + private String payOrderId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 应用ID + */ + private String appId; + + /** + * 商户退款单号(商户系统的订单号) + */ + private String mchRefundNo; + + /** + * 支付金额,单位分 + */ + private Long payAmount; + + /** + * 退款金额,单位分 + */ + private Long refundAmount; + + /** + * 三位货币代码,人民币:cny + */ + private String currency; + + /** + * 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败 + */ + private Byte state; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 渠道错误码 + */ + private String errCode; + + /** + * 渠道错误描述 + */ + private String errMsg; + + /** + * 扩展参数 + */ + private String extParam; + + /** + * 订单退款成功时间 + */ + private Long successTime; + + /** + * 创建时间 + */ + private Long createdAt; + + + public static QueryRefundOrderRS buildByRefundOrder(RefundOrder refundOrder){ + + if(refundOrder == null){ + return null; + } + + QueryRefundOrderRS result = new QueryRefundOrderRS(); + BeanUtils.copyProperties(refundOrder, result); + result.setSuccessTime(refundOrder.getSuccessTime() == null ? null : refundOrder.getSuccessTime().getTime()); + result.setCreatedAt(refundOrder.getCreatedAt() == null ? null : refundOrder.getCreatedAt().getTime()); + return result; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRQ.java new file mode 100644 index 0000000..5d39092 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRQ.java @@ -0,0 +1,68 @@ +package com.jeequan.jeepay.core.model.rqrs.refund; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.entity.PayOrder; +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/* +* 创建退款订单请求参数对象 +* +* @author terrfly +* +* @date 2021/6/16 15:41 +*/ +@Data +@Accessors(chain = true) +public class RefundOrderRQ extends AbstractMchAppRQ { + + /** 商户订单号 **/ + private String mchOrderNo; + + /** 支付系统订单号 **/ + private String payOrderId; + + /** 商户系统生成的退款单号 **/ + @NotBlank(message="商户退款单号不能为空") + private String mchRefundNo; + + /** 退款金额, 单位:分 **/ + @NotNull(message="退款金额不能为空") + @Min(value = 1, message = "退款金额请大于1分") + private Long refundAmount; + + /** 货币代码 **/ + @NotBlank(message="货币代码不能为空") + private String currency; + + /** 退款原因 **/ + @NotBlank(message="退款原因不能为空") + private String refundReason; + + /** 客户端IP地址 **/ + private String clientIp; + + /** 异步通知地址 **/ + private String notifyUrl; + + /** 特定渠道发起额外参数 **/ + private String channelExtra; + + /** 商户扩展参数 **/ + private String extParam; + + /** 渠道特殊业务数据 **/ + private String channelBizData; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_REFUND_ORDER; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRS.java new file mode 100644 index 0000000..bab314d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/refund/RefundOrderRS.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.core.model.rqrs.refund; + +import com.jeequan.jeepay.core.entity.RefundOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +/* +* 退款订单 响应参数 +* +* @author terrfly +* +* @date 2021/6/16 15:41 +*/ +@Data +public class RefundOrderRS extends AbstractRS { + + /** 支付系统退款订单号 **/ + private String refundOrderId; + + /** 商户发起的退款订单号 **/ + private String mchRefundNo; + + /** 订单支付金额 **/ + private Long payAmount; + + /** 申请退款金额 **/ + private Long refundAmount; + + /** 退款状态 **/ + private Byte state; + + /** 渠道退款单号 **/ + private String channelOrderNo; + + /** 渠道返回错误代码 **/ + private String errCode; + + /** 渠道返回错误信息 **/ + private String errMsg; + + + public static RefundOrderRS buildByRefundOrder(RefundOrder refundOrder){ + + if(refundOrder == null){ + return null; + } + + RefundOrderRS result = new RefundOrderRS(); + BeanUtils.copyProperties(refundOrder, result); + + return result; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/settle/ChannelSettleRq.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/settle/ChannelSettleRq.java new file mode 100644 index 0000000..d06a05c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/settle/ChannelSettleRq.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.core.model.rqrs.settle; + +import com.alibaba.fastjson.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * TODO + * + * @author crystal + * @date 2023/12/6 16:48 + */ +@Data +@AllArgsConstructor +public class ChannelSettleRq { + + public final static Long DETAULT_PAGE = 1L; + + public final static Long DETAULT_PAGE_SIZE = 50L; + + /** + * 商户号集合 + */ + private List mercNos; + + /** + * 通道商户号 + */ + private String mercNo; + /** + * 开始日期 + */ + private Date startDate; + + /** + * 结束日期 + */ + private Date endDate; + /** + * 当前页 + */ + private Long page; + + /** + * 条数 + */ + private Long size; + + /** + * + */ + private String billNo; + + /** + * 扩展参数 + */ + private JSONObject ext; + + /** + * 扩展商户号 + */ + private String extMchNo; + + /** + * 交易日期范围 + */ + private String transDateScope; + + public ChannelSettleRq(String mercNo, Date startDate, Date endDate, Long page, Long size) { + this.mercNo = mercNo; + this.startDate = startDate; + this.endDate = endDate; + this.page = page; + this.size = size; + } + + public ChannelSettleRq(String channelMchNo, String billNo,Date startDate,Date endDate,String transDateScope) { + this(channelMchNo,startDate,endDate,DETAULT_PAGE,DETAULT_PAGE_SIZE); + this.billNo = billNo; + this.transDateScope = transDateScope; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRQ.java new file mode 100644 index 0000000..57e6394 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/* +* 查询转账单请求参数对象 +* +* @author terrfly +* +* @date 2021/6/17 14:07 +*/ +@Data +public class QueryTransferBalanceRQ extends AbstractMchAppRQ { + + /** 支付接口代码 **/ + @NotBlank(message="支付接口代码不能为空") + private String ifCode; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_TRANS_BALANCE_QUERY; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRS.java new file mode 100644 index 0000000..875361b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferBalanceRS.java @@ -0,0 +1,19 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; + +/* +* 查询转账可用余额 响应参数 +* +* @author zx +* +* @date 2021/6/8 17:34 +*/ +@Data +public class QueryTransferBalanceRS extends AbstractRS { + + /** 转账可用余额 **/ + private Long balanceAmount; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRQ.java new file mode 100644 index 0000000..c699afd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRQ.java @@ -0,0 +1,28 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +/* +* 查询转账单请求参数对象 +* +* @author terrfly +* +* @date 2021/6/17 14:07 +*/ +@Data +public class QueryTransferOrderRQ extends AbstractMchAppRQ { + + /** 商户转账单号 **/ + private String mchOrderNo; + + /** 支付系统转账单号 **/ + private String transferId; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_TRANS_ORDER_QUERY; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRS.java new file mode 100644 index 0000000..b4051ea --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/QueryTransferOrderRS.java @@ -0,0 +1,133 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +/* +* 查询转账订单 响应参数 +* +* @author terrfly +* +* @date 2021/6/17 14:08 +*/ +@Data +public class QueryTransferOrderRS extends AbstractRS { + + /** + * 转账订单号 + */ + private String transferId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 应用ID + */ + private String appId; + + /** + * 商户订单号 + */ + private String mchOrderNo; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 入账方式: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡 + */ + private String entryType; + + /** + * 转账金额,单位分 + */ + private Long amount; + + /** + * 三位货币代码,人民币:cny + */ + private String currency; + + /** + * 收款账号 + */ + private String accountNo; + + /** + * 收款人姓名 + */ + private String accountName; + + /** + * 收款人开户行名称 + */ + private String bankName; + + /** + * 转账备注信息 + */ + private String transferDesc; + + /** + * 支付状态: 0-订单生成, 1-转账中, 2-转账成功, 3-转账失败, 4-订单关闭 + */ + private Byte state; + + /** + * 特定渠道发起额外参数 + */ + private String channelExtra; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 渠道支付错误码 + */ + private String errCode; + + /** + * 渠道支付错误描述 + */ + private String errMsg; + + /** + * 商户扩展参数 + */ + private String extParam; + + /** + * 转账成功时间 + */ + private Long successTime; + + /** + * 创建时间 + */ + private Long createdAt; + + + public static QueryTransferOrderRS buildByRecord(TransferOrder record){ + + if(record == null){ + return null; + } + + QueryTransferOrderRS result = new QueryTransferOrderRS(); + BeanUtils.copyProperties(record, result); + result.setSuccessTime(record.getSuccessTime() == null ? null : record.getSuccessTime().getTime()); + result.setCreatedAt(record.getCreatedAt() == null ? null : record.getCreatedAt().getTime()); + return result; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRQ.java new file mode 100644 index 0000000..3d14384 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRQ.java @@ -0,0 +1,77 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.rqrs.AbstractMchAppRQ; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/* +* 申请转账 请求参数 +* +* @author terrfly +* +* @date 2021/8/10 11:31 +*/ +@Data +public class TransferOrderRQ extends AbstractMchAppRQ { + + /** 商户订单号 **/ + @NotBlank(message="商户订单号不能为空") + private String mchOrderNo; + + /** 商户号不能为空 **/ + @NotBlank(message="商户号不能为空") + private String mchNo; + + /** 支付接口代码 **/ + @NotBlank(message="支付接口代码不能为空") + private String ifCode; + + /** 入账方式 **/ + @NotBlank(message="入账方式不能为空") + private String entryType; + + /** 支付金额, 单位:分 **/ + @NotNull(message="转账金额不能为空") + @Min(value = 1, message = "转账金额不能小于1分") + private Long amount; + + /** 货币代码 **/ + @NotBlank(message="货币代码不能为空") + private String currency; + + /** 收款账号 **/ + @NotBlank(message="收款账号不能为空") + private String accountNo; + + /** 收款人姓名 **/ + private String accountName; + + /** 收款人开户行名称 **/ + private String bankName; + + /** 客户端IP地址 **/ + private String clientIp; + + /** 转账备注信息 **/ + @NotBlank(message="转账备注信息不能为空") + private String transferDesc; + + /** 异步通知地址 **/ + private String notifyUrl; + + /** 特定渠道发起额外参数 **/ + private String channelExtra; + + /** 商户扩展参数 **/ + private String extParam; + + @Override + public String apiName() { + return CS.MCH_APP_API_ENUM.API_TRANS_ORDER; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRS.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRS.java new file mode 100644 index 0000000..14b31be --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/TransferOrderRS.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer; + +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.model.rqrs.AbstractRS; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +/* +* 创建订单(统一订单) 响应参数 +* +* @author terrfly +* +* @date 2021/6/8 17:34 +*/ +@Data +public class TransferOrderRS extends AbstractRS { + + + /** 转账单号 **/ + private String transferId; + + /** 商户单号 **/ + private String mchOrderNo; + + /** 转账金额 **/ + private Long amount; + + /** + * 收款账号 + */ + private String accountNo; + + /** + * 收款人姓名 + */ + private String accountName; + + /** + * 收款人开户行名称 + */ + private String bankName; + + /** 状态 **/ + private Byte state; + + /** 渠道退款单号 **/ + private String channelOrderNo; + + /** 渠道返回错误代码 **/ + private String errCode; + + /** 渠道返回错误信息 **/ + private String errMsg; + + public static TransferOrderRS buildByRecord(TransferOrder record){ + + if(record == null){ + return null; + } + + TransferOrderRS result = new TransferOrderRS(); + BeanUtils.copyProperties(record, result); + + return result; + } + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/channel/SumapayTransferRQ.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/channel/SumapayTransferRQ.java new file mode 100644 index 0000000..03e6f01 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/rqrs/transfer/channel/SumapayTransferRQ.java @@ -0,0 +1,29 @@ +package com.jeequan.jeepay.core.model.rqrs.transfer.channel; + +import com.jeequan.jeepay.core.model.rqrs.transfer.TransferOrderRQ; +import lombok.Data; + +/* +* 支付接口: 丰付支付 +* +* @author zx +* +* @date 2022/12/29 17:34 +*/ +@Data +public class SumapayTransferRQ extends TransferOrderRQ { + + /** 银行编码 **/ + private String bankCode; + /** 开户省 **/ + private String openBankProvince; + /** 开户市 **/ + private String openBankCity; + /** 开户网点 **/ + private String openBankName; + /** 联行号 **/ + private String unionBankNum; + /** 付款审核类型, 0:手工审核 1:自动实时 **/ + private String transferPayType; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/security/JeeUserDetails.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/security/JeeUserDetails.java new file mode 100644 index 0000000..e903c1b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/security/JeeUserDetails.java @@ -0,0 +1,157 @@ +package com.jeequan.jeepay.core.model.security; + +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.jwt.JWTPayload; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/* +* 实现Spring Security的UserDetails接口 +* +* @author terrfly +* +* @date 2021/6/8 16:34 +*/ +@Slf4j +@Data +public class JeeUserDetails implements UserDetails { + + /** 系统用户信息 **/ + private SysUser sysUser; + + /** 密码 **/ + private String credential; + + /** 角色+权限 集合 (角色必须以: ROLE_ 开头) **/ + private Collection authorities = new ArrayList<>(); + + /** 缓存标志 **/ + private String cacheKey; + + /** 登录类型 */ + private String loginType; + + /** 登录IP **/ + private String loginIp; + + /** 商户类型 **/ + private Byte mchType; + + /** 认证类型,见 CREDENTIAL_AUTH_TYPE **/ + private String authType; + + /** 门店ID列表 **/ + private List storeIdList; + + /** 登录服务商/商户/平台状态 **/ + private Byte infoState; + + //此处的无参构造,为json反序列化提供 + public JeeUserDetails() { + } + + public JeeUserDetails(SysUser sysUser, String credential) { + + this.setSysUser(sysUser); + this.setCredential(credential); + + //做一些初始化操作 + } + + public JeeUserDetails(SysUser sysUser, String credential, List storeIdList) { + this.setSysUser(sysUser); + this.setCredential(credential); + this.setStoreIdList(storeIdList); + //做一些初始化操作 + } + + public JeeUserDetails(SysUser sysUser, String credential, Byte infoState) { + this.setSysUser(sysUser); + this.setCredential(credential); + this.setInfoState(infoState); + //做一些初始化操作 + } + + /** spring-security 需要验证的密码 **/ + @Override + public String getPassword() { + return getCredential(); + } + + /** spring-security 登录名 **/ + @Override + public String getUsername() { + return getSysUser().getSysUserId() + ""; + } + + /** 账户是否过期 **/ + @Override + public boolean isAccountNonExpired() { + return true; + } + + /** 账户是否已解锁 **/ + @Override + public boolean isAccountNonLocked() { + return true; + } + + /** 密码是否过期 **/ + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + /** 账户是否开启 **/ + @Override + public boolean isEnabled() { + return true; + } + + /** 获取权限集合 **/ + @Override + public Collection getAuthorities() { + return authorities; + } + + public static JeeUserDetails getCurrentUserDetails() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + return null; + } + + try { + return (JeeUserDetails) authentication.getPrincipal(); + }catch (Exception e) { + return null; + } + } + + + // 判断是否app登录 + public boolean isAppLogin(){ + return JWTPayload.LOGIN_PAGE_TYPE.APP.equals(getLoginType()) || JWTPayload.LOGIN_PAGE_TYPE.LITE.equals(getLoginType()); + } + + + /** 是否扩展员登录 **/ + public boolean isEpUser(){ + return this.getSysUser() != null && this.getSysUser().getUserType() != null && this.getSysUser().getUserType() == SysUser.UEST_TYPE_EXPAND; + } + + /** 获取当前登录者ID **/ + public Long getSysUserId(){ + return this.getSysUser() != null ? this.getSysUser().getSysUserId() : null; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AbstractSmsConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AbstractSmsConfig.java new file mode 100644 index 0000000..54ad64d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AbstractSmsConfig.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import com.alibaba.fastjson.JSON; +import com.jeequan.jeepay.core.constants.CS; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.regex.Pattern; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class AbstractSmsConfig { + + public static AbstractSmsConfig getSmsConfig(String smsProvideKey, String configVal){ + + if(CS.SMS_PROVIDER_TYPE_API_ENUM.SMS_PROVIDE_KEY_ALIYUNDY.equals(smsProvideKey)){ + return JSON.parseObject(configVal, AliyundySmsConfig.class); + } + + if(CS.SMS_PROVIDER_TYPE_API_ENUM.SMS_PROVIDE_KEY_JEEPAYDX.equals(smsProvideKey)){ + return JSON.parseObject(configVal, JeepaydxSmsConfig.class); + } + + if (CS.SMS_PROVIDER_TYPE_API_ENUM.SMS_PROVIDE_KEY_JUHEDX.equals(smsProvideKey)) { + return JSON.parseObject(configVal, JuhedxSmsConfig.class); + } + + if(CS.SMS_PROVIDER_TYPE_API_ENUM.SMS_PROVIDE_KEY_MOCKTEST.equals(smsProvideKey)){ + return JSON.parseObject(configVal, MocktestSmsConfig.class); + } + + return null; + } + + + /** + * 验证手机号码,11位数字,1开头 * + * @param mobileNumber + * @return + */ + public static boolean checkMobileNumber(String mobileNumber) { + boolean flag = false; + try { + Pattern regex = Pattern.compile("^1\\d{10}$"); + flag = regex.matcher(mobileNumber).matches(); + } catch (Exception ignored) { + + } + return flag; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AliyundySmsConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AliyundySmsConfig.java new file mode 100644 index 0000000..04a6634 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/AliyundySmsConfig.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import com.alibaba.fastjson.JSON; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; + +/** + * application.yml 移植到DB中的配置变量 阿里大于短信配置 + **/ +@Data +@Slf4j +public class AliyundySmsConfig extends AbstractSmsConfig implements Serializable { + + public static final String endpointName = "cn-hangzhou"; + + public static final String regionId = "cn-hangzhou"; + + /** 产品名称:云通信短信API产品,开发者无需替换 **/ + public static final String product = "Dysmsapi"; + + /** 产品域名,开发者无需替换 **/ + public static final String domain = "dysmsapi.aliyuncs.com"; + + public static final byte BIZ_TYPE_REGISTER = 10; + + + public static AliyundySmsConfig parse(String val){ + + if(StringUtils.isEmpty(val)){ + return null; + } + + try { + return JSON.parseObject(val, AliyundySmsConfig.class); + } catch (Exception e) { + log.error("【阿里大于短信配置】数据转换异常", e); + return null; + } + } + + + /** id **/ + private String accessKeyId; + + /** key **/ + private String accessKeySecret; + + /** 签名串 **/ + private String signName; + + /** 忘记密码模板ID **/ + private String forgetPwdTemplateId; + + /** 商户注册模板ID **/ + private String registerMchTemplateId; + + /** 商户登录模板ID **/ + private String loginMchTemplateId; + + /** 账号开通提醒模板ID **/ + private String accountOpenTemplateId; + + /** 会员手机号绑定模板ID **/ + private String mbrTelBindTemplateId; + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JeepaydxSmsConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JeepaydxSmsConfig.java new file mode 100644 index 0000000..fda1b85 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JeepaydxSmsConfig.java @@ -0,0 +1,37 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; + +/** + * application.yml 移植到DB中的配置变量 + **/ +@Data +@Slf4j +public class JeepaydxSmsConfig extends AbstractSmsConfig implements Serializable { + + private static final String SMS_GATEWAY = "https://sdk.clysz.cn/v7"; + + // 【计全短信】发送接口 + public static final String SMS_SEND = "/msg/submit.json"; + // 【计全短信】余额查询接口 + public static final String SMS_BALANCE_QUERY = "/balance/query.json"; + + public static String getSmsUrl(String uri){ + return SMS_GATEWAY + uri; + } + + /** 查询相关业务类型 **/ + public static final String SMS_QUERY_TYPE = "balance"; + + /** 用户名 **/ + private String userName; + + /** 密码 **/ + private String accountPwd; + + /** 签名 **/ + private String signName; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JuhedxSmsConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JuhedxSmsConfig.java new file mode 100644 index 0000000..777b26f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/JuhedxSmsConfig.java @@ -0,0 +1,46 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; + +/** + * 聚合数据短信配置文件 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Slf4j +public class JuhedxSmsConfig extends AbstractSmsConfig implements Serializable { + + private static final String SMS_GATEWAY = "https://v.juhe.cn/"; + + public static final String SMS_SEND = "sms/send"; + + public static final int SUCCESS_CODE = 0; + + private String accessKeyId; + + public static String getSmsUrl(String uri){ + return SMS_GATEWAY + uri; + } + + /** 忘记密码模板ID **/ + private String forgetPwdTemplateId; + + /** 商户注册模板ID **/ + private String registerMchTemplateId; + + /** 商户登录模板ID **/ + private String loginMchTemplateId; + + /** 账号开通提醒模板ID **/ + private String accountOpenTemplateId; + + /** 会员手机号绑定模板ID **/ + private String mbrTelBindTemplateId; + + /** 账户余额不足通知模板id **/ + private String accountBalanceTemplateId; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/MocktestSmsConfig.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/MocktestSmsConfig.java new file mode 100644 index 0000000..eb10f1d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/MocktestSmsConfig.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.io.Serializable; + +/*** +* mocktest 短信通道 +* +* @author terrfly +* +* @date 2023/8/18 16:33 +*/ +@Data +@Slf4j +public class MocktestSmsConfig extends AbstractSmsConfig implements Serializable { + + /** 验证码 **/ + private String mockCode; + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizDiyContentModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizDiyContentModel.java new file mode 100644 index 0000000..20382c7 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizDiyContentModel.java @@ -0,0 +1,45 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +/** 自定义模版信息 **/ +@Data +public class SmsBizDiyContentModel extends JSONObject { + + public static final String FIELD_LOGIN_NAME = "loginName"; + public static final String FIELD_USER_PWD = "userPwd"; + + /** 手机号 **/ + private String phoneNo; + + /** 模版类型 **/ + private String smsBizType; + + /** 构造创建用户信息模版 **/ + public static SmsBizDiyContentModel genUserOpenAccount(String phoneNo, String loginName, String userPwd){ + + SmsBizDiyContentModel result = new SmsBizDiyContentModel(); + + result.setPhoneNo(phoneNo); + result.setSmsBizType(CS.SMS_TYPE_API_ENUM.TYPE_ACCOUNT_OPEN); // 商户开户 + + result.put(FIELD_LOGIN_NAME, loginName); + result.put(FIELD_USER_PWD, StringUtils.defaultIfEmpty(userPwd, "默认密码")); + return result; + } + + + /** 构建通用模板 **/ + public static SmsBizDiyContentModel genModel(String phoneNo, String smsBizType, JSONObject extra){ + + SmsBizDiyContentModel result = new SmsBizDiyContentModel(); + result.setPhoneNo(phoneNo); + result.setSmsBizType(smsBizType); + result.putAll(extra); + return result; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizVercodeModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizVercodeModel.java new file mode 100644 index 0000000..2ef3775 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/smsconfig/SmsBizVercodeModel.java @@ -0,0 +1,30 @@ +package com.jeequan.jeepay.core.model.smsconfig; + +import com.alibaba.fastjson.JSON; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +/** 短信验证码的缓存存放数据 **/ +@Data +@AllArgsConstructor +@Builder +public class SmsBizVercodeModel{ + + /** 手机号 **/ + private String phoneNo; + + /** 验证码 **/ + private String smsVercode; + + /** 业务类型 **/ + private String smsBizType; + + /** 过期时间 **/ + private int expiredMin; + + + public String toJSONString(){ + return JSON.toJSONString(this); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/terminal/TerminalChannelModel.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/terminal/TerminalChannelModel.java new file mode 100644 index 0000000..c871da2 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/terminal/TerminalChannelModel.java @@ -0,0 +1,34 @@ +package com.jeequan.jeepay.core.model.terminal; + +import lombok.Data; +import lombok.experimental.Accessors; + +/*** +* 终端渠道绑定设备 model +* +* @author terrfly +* +* @date 2022/4/29 10:18 +*/ +@Data +@Accessors(chain = true) +public class TerminalChannelModel { + + public static final byte STATE_NOT_BIND = 0; + public static final byte STATE_SUCCESS = 1; + public static final byte STATE_FAIL = 2; + + /** 终端编号(jeepay系统内,商户自行录入的编号) **/ + private String trmNo; + + /** 渠道终端编号( 由上游返回的数据信息 ) **/ + private String channelTrmNo; + + // 状态 + private Byte state; + + /** 错误信息 **/ + public String errInfo; + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/tranfer/TransferBasicInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/tranfer/TransferBasicInfo.java new file mode 100644 index 0000000..e76383f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/tranfer/TransferBasicInfo.java @@ -0,0 +1,40 @@ +package com.jeequan.jeepay.core.model.tranfer; + +/** + * 转账发起方、接收方资料 + * + * @author deng + * @since 2024/4/25 + */ +public class TransferBasicInfo { + + /** + * 对公、企业 + */ + public static final String ACCOUNT_TYPE_COR = "B"; + /** + * 对私、个人 + */ + public static final String ACCOUNT_TYPE_PRI = "C"; + + /** + * 微信 + */ + public static final String ENTRY_TYPE_WX = "WX"; + /** + * 支付宝 + */ + public static final String ENTRY_TYPE_ZFB = "ZFB"; + /** + * 银行账户 + */ + public static final String ENTRY_TYPE_BANK = "BANK"; + + private String accountNo; + + private String accountName; + + private String entryType; + + private String accountType; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/vo/MchThirdParamResult.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/vo/MchThirdParamResult.java new file mode 100644 index 0000000..2e4b335 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/vo/MchThirdParamResult.java @@ -0,0 +1,47 @@ +package com.jeequan.jeepay.core.model.vo; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * TODO + * + * @author crystal + * @date 2023/12/1 17:25 + */ +@Data +@NoArgsConstructor +public class MchThirdParamResult { + + + private String wxSubMchNo; + + private String zfbSubMchNo; + + @TableField(exist = false) + private List wxAppidList; + + @TableField(exist = false) + private List wxPathList; + + /** + * 电子围栏标记,1,开启,0,未开启 + */ + private String regionLock; + + /** + * 反扫权限 + */ + private int scanPayPermFlag; + + public MchThirdParamResult(String wxSubMchNo,String zfbSubMchNo, List wxAppidList, List wxPathList) { + this.wxSubMchNo = wxSubMchNo; + this.zfbSubMchNo = zfbSubMchNo; + this.wxAppidList = wxAppidList; + this.wxPathList = wxPathList; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/WxAccessToken.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/WxAccessToken.java new file mode 100644 index 0000000..790728f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/WxAccessToken.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.core.model.wx; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +/** + * 微信公众号/小程序接口调用凭证 accessToken + * @author zx + * @date 2020-10-11 + */ +@Data +public class WxAccessToken { + + /** + * 凭证 + */ + @JSONField(name = "access_token") + private String accessToken; + + /** + * 凭证有效时间,单位:秒 + */ + @JSONField(name = "expires_in") + private Long expiresIn; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/wxmp/WxUserInfo.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/wxmp/WxUserInfo.java new file mode 100644 index 0000000..a3b4e16 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/model/wx/wxmp/WxUserInfo.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.model.wx.wxmp; + +import lombok.Data; + +/** + * 微信oauth2用户个人信息. + * @author zx + * @date 2020-10-11 + */ +@Data +public class WxUserInfo { + + /** + * openid 用户的标识 + */ + private String openid; + /** + * nickname 用户昵称 + */ + private String nickname; + /** + * headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像), + * 用户没有头像时该项为空 + */ + private String headImgUrl; + /** + * unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 + */ + private String unionId; + + /** + * privilege 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) + */ + private String[] privileges; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/rpc/readme.txt b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/rpc/readme.txt new file mode 100644 index 0000000..cb975b9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/rpc/readme.txt @@ -0,0 +1,11 @@ +rpc相关的定义 + +比如 接口类, model等。 + +rpc + interfaces + 业务1Interface + 业务2文件夹(非必要不新建) + models + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/IOpenApiService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/IOpenApiService.java new file mode 100644 index 0000000..73f9904 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/IOpenApiService.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.service; + +import com.jeequan.jeepay.core.exception.AccessMsgException; +import com.jeequan.jeepay.core.model.openapi.AccessReq; +import com.jeequan.jeepay.core.model.openapi.AccessResp; + +/** + * + * @author crystal + * @date 2024/4/8 10:43 + */ +public interface IOpenApiService { + + /** + * 通用接口 + * @param request + * @return + * @throws AccessMsgException + */ + AccessResp execute(AccessReq request) throws AccessMsgException; + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ISysConfigService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ISysConfigService.java new file mode 100644 index 0000000..8ea07c4 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ISysConfigService.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.core.service; + +import cn.hutool.crypto.symmetric.SM4; +import com.jeequan.jeepay.core.model.*; + +public interface ISysConfigService { + + /** 获取应用的配置参数 **/ + DBApplicationConfig getDBApplicationConfig(); + + /** 获取公众号消息配置参数 **/ + DBWxMpConfig getDBWxMpConfig(); + + /** 获取OCR配置参数 **/ + DBOCRConfig getOcrConfig(); + + /** 获取OSS配置参数 **/ + DBOSSConfig getOssConfig(); + + /** 获取OSS配置参数 **/ + DBOEMConfig getOemConfig(); + + /** 获取app push配置参数 **/ + DBAppPushConfig getDBAppPushConfig(); + + /** 获取百度语音配置参数 **/ + DBBaiduBceConfig getDBBaiduBceConfig(); + + /** 获取隐私政策与服务协议配置参数 **/ + DBTreatyConfig getTreatyConfig(); + + /** 高德地图 配置参数 **/ + DBApiMapConfig getDBApiMapConfig(); + + /** 系统安全 配置参数 **/ + DBsecurityConfig getDBSecurityConfig(); + + /** 默认配置 配置参数 **/ + DBDefaultConfig getDBDefaultConfig(); + + /** 获取SM4对象(http请求参数相关) **/ + SM4 getHttpMessageSM4(); + + /** 获取邮件配置参数 **/ + DBEmailConfig getEmailConfig(); + + /** 获取营销 配置参数 **/ + DBMarketingConfig getDBMarketingConfig(); + + /** + * 获取付款配置参数 + * @return + */ + DBPaymentConfig getDbPaymentConfig(); + + + /** + * 获取平台营销红包是否配置 + * @return + */ + Boolean getDbMarketPlatRedPacket(); + + /** + * 生成token + * @param type + * @param id + * @param amt + * @return + */ + String genQrToken(Byte type, String id,Long amt); +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ValidatorService.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ValidatorService.java new file mode 100644 index 0000000..4c4af54 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/service/ValidatorService.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.service; + +import com.jeequan.jeepay.core.exception.BizException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import javax.validation.ConstraintViolation; +import java.util.Set; + +/** + * TODO + * + * @author deng + * @since 2024/5/9 + */ +@Service +public class ValidatorService { + + @Autowired + private LocalValidatorFactoryBean validatorFactoryBean; + + public void validate(T subject, Class... groupClass) { + Set> validate = validatorFactoryBean.validate(subject, groupClass); + if (!validate.isEmpty()) { + StringBuilder validError = new StringBuilder(); + validate.forEach(item -> validError.append(item.getMessage()).append(",")); + throw new BizException(validError.subSequence(0, validError.length() - 1).toString()); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsHandler.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsHandler.java new file mode 100644 index 0000000..0e9c089 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsHandler.java @@ -0,0 +1,72 @@ +package com.jeequan.jeepay.core.sms; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.model.smsconfig.AbstractSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.AliyundySmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizVercodeModel; +import com.jeequan.jeepay.core.utils.DateKit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/*** + * 阿里大于 短信通道 + * + * @author terrfly + * @date 2023/8/18 16:34 + */ +@Slf4j +@Service +public class AliyundySmsHandler implements ISmsHandler { + + + @Override + public void sendVercode(SmsBizVercodeModel smsBizVercodeModel, AbstractSmsConfig smsConfig) { + + AliyundySmsConfig aliyundySmsConfig = (AliyundySmsConfig)smsConfig; + + String smsTemplateId = ""; + if (CS.SMS_TYPE_API_ENUM.TYPE_AUTH.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = aliyundySmsConfig.getLoginMchTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_REGISTER.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = aliyundySmsConfig.getRegisterMchTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_RETRIEVE.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = aliyundySmsConfig.getForgetPwdTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_MBR_TEL_BIND.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = aliyundySmsConfig.getMbrTelBindTemplateId(); + } + + // 生成短信验证码 + String verifyCode = smsBizVercodeModel.getSmsVercode(); + JSONObject codeObj = new JSONObject(); + codeObj.put("mobile", smsBizVercodeModel.getPhoneNo()); + codeObj.put("code", verifyCode); + codeObj.put("time", DateKit.currentTimeMillis()); + + AliyundySmsProcessKit.callInterface(aliyundySmsConfig, smsTemplateId, smsBizVercodeModel.getPhoneNo(), codeObj.toJSONString()); + + } + + @Override + public void sendDiyContent(SmsBizDiyContentModel smsBizDiyContentModel, AbstractSmsConfig smsConfig) { + + AliyundySmsConfig aliyundySmsConfig = (AliyundySmsConfig)smsConfig; + + JSONObject codeObj = new JSONObject(); + if(CS.SMS_TYPE_API_ENUM.TYPE_ACCOUNT_OPEN.equals(smsBizDiyContentModel.getSmsBizType())){ + codeObj.put("loginName", smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_LOGIN_NAME)); + codeObj.put("loginPwd", smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_USER_PWD)); + + } + + AliyundySmsProcessKit.callInterface(aliyundySmsConfig, aliyundySmsConfig.getAccountOpenTemplateId(), smsBizDiyContentModel.getPhoneNo(), codeObj.toJSONString()); + + } + + @Override + public String querySmsInfo(AbstractSmsConfig smsConfig, String bizQueryType) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsProcessKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsProcessKit.java new file mode 100644 index 0000000..208997e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/AliyundySmsProcessKit.java @@ -0,0 +1,65 @@ +package com.jeequan.jeepay.core.sms; + +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.smsconfig.AliyundySmsConfig; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +/*** + * 阿里大于 实现, 避免 其他项目引用报错 + * + * @author terrfly + * @date 2023/8/18 16:34 + */ +@Slf4j +public class AliyundySmsProcessKit{ + + public static boolean callInterface(AliyundySmsConfig smsConfig, String templateId, String phone, String templateVal){ + + try { + + if (smsConfig == null || StringUtils.isEmpty(templateId)) { + return false; + } + log.info("读取短信配置:短信签名:{}", smsConfig.getSignName()); + //可自助调整超时时间 + System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); + System.setProperty("sun.net.client.defaultReadTimeout", "10000"); + + //初始化acsClient,暂不支持region化 + IClientProfile profile = DefaultProfile.getProfile(AliyundySmsConfig.regionId, smsConfig.getAccessKeyId(), smsConfig.getAccessKeySecret()); + DefaultProfile.addEndpoint(AliyundySmsConfig.endpointName, AliyundySmsConfig.regionId, AliyundySmsConfig.product, AliyundySmsConfig.domain); + IAcsClient acsClient = new DefaultAcsClient(profile); + + //组装请求对象-具体描述见控制台-文档部分内容 + SendSmsRequest request = new SendSmsRequest(); + //必填:待发送手机号 + request.setPhoneNumbers(phone); + //必填:短信签名-可在短信控制台中找到 + request.setSignName(smsConfig.getSignName()); + //必填:短信模板-可在短信控制台中找到 + request.setTemplateCode(templateId); + //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 + request.setTemplateParam(templateVal); + + //hint 此处可能会抛出异常,注意catch + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + + log.info("调用阿里短信服务完成.phone={},code={},message={},requestId={},bizId={}", phone, + sendSmsResponse.getCode(), sendSmsResponse.getMessage(), sendSmsResponse.getRequestId(), sendSmsResponse.getBizId()); + + return true; + + } catch (Exception e) { + + log.info("短信异常:", e); + throw new BizException("短信发送失败"); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/ISmsHandler.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/ISmsHandler.java new file mode 100644 index 0000000..b6c2c69 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/ISmsHandler.java @@ -0,0 +1,24 @@ +package com.jeequan.jeepay.core.sms; + +import com.jeequan.jeepay.core.model.smsconfig.AbstractSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizVercodeModel; + +public interface ISmsHandler { + + /** + * 发送短信验证码 + * */ + void sendVercode(SmsBizVercodeModel smsBizVercodeModel, AbstractSmsConfig smsConfig); + + /** + * 发送自定义内容的短信 + * */ + void sendDiyContent(SmsBizDiyContentModel smsBizDiyContentModel, AbstractSmsConfig smsConfig); + + /** + * 查询短信相关信息(smsConfig:短信配置, bizQueryType:业务类型) + * */ + String querySmsInfo(AbstractSmsConfig smsConfig, String bizQueryType); + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JeepaydxSmsHandler.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JeepaydxSmsHandler.java new file mode 100644 index 0000000..dbe8b81 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JeepaydxSmsHandler.java @@ -0,0 +1,148 @@ +package com.jeequan.jeepay.core.sms; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.smsconfig.AbstractSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.JeepaydxSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizVercodeModel; +import com.jeequan.jeepay.core.utils.JeepayKit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +/** + * 计全短信配置 + **/ +@Slf4j +@Service +public class JeepaydxSmsHandler implements ISmsHandler { + + @Override + public void sendVercode(SmsBizVercodeModel smsBizVercodeModel, AbstractSmsConfig smsConfig) { + JeepaydxSmsConfig jeepaydxSmsConfig = (JeepaydxSmsConfig)smsConfig; + // 生成短信验证码 + String verifyCode = smsBizVercodeModel.getSmsVercode(); + // 短信内容 + String templateVal = ""; + if (CS.SMS_TYPE_API_ENUM.TYPE_AUTH.equals(smsBizVercodeModel.getSmsBizType())) { + templateVal = "您正在进行登录, 验证码为:" + verifyCode + ",该验证码 " + smsBizVercodeModel.getExpiredMin() + " 分钟内有效,请勿泄漏于他人。"; + }else if (CS.SMS_TYPE_API_ENUM.TYPE_REGISTER.equals(smsBizVercodeModel.getSmsBizType())) { + templateVal = "您正在进行注册, 验证码为:" + verifyCode + ",该验证码 " + smsBizVercodeModel.getExpiredMin() + " 分钟内有效,请勿泄漏于他人。"; + }else if (CS.SMS_TYPE_API_ENUM.TYPE_RETRIEVE.equals(smsBizVercodeModel.getSmsBizType())) { + templateVal = "您正在找回密码操作, 验证码为:" + verifyCode + ",该验证码 " + smsBizVercodeModel.getExpiredMin() + " 分钟内有效,请勿泄漏于他人。"; + }else if (CS.SMS_TYPE_API_ENUM.TYPE_MBR_TEL_BIND.equals(smsBizVercodeModel.getSmsBizType())) { + templateVal = "您正在进行会员绑定操作, 验证码为:" + verifyCode + ",该验证码 " + smsBizVercodeModel.getExpiredMin() + " 分钟内有效,请勿泄漏于他人。"; + } + this.callInterface(jeepaydxSmsConfig, smsBizVercodeModel.getPhoneNo(), templateVal); + + } + + @Override + public void sendDiyContent(SmsBizDiyContentModel smsBizDiyContentModel, AbstractSmsConfig smsConfig) { + JeepaydxSmsConfig jeepaydxSmsConfig = (JeepaydxSmsConfig)smsConfig; + String templateVal = ""; + if (CS.SMS_TYPE_API_ENUM.TYPE_ACCOUNT_OPEN.equals(smsBizDiyContentModel.getSmsBizType())) { + templateVal = "账号:" + smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_LOGIN_NAME) + + ",密码:" + smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_USER_PWD) + ",您的账户已开通成功,请勿泄漏于他人。"; + } + this.callInterface(jeepaydxSmsConfig, smsBizDiyContentModel.getPhoneNo(), templateVal); + } + + public boolean callInterface(JeepaydxSmsConfig smsConfig, String phone, String templateVal){ + String logPrefix = "[计全短信发送]"; + try { + JSONObject reqJson = new JSONObject(); + // 用户名 + reqJson.put("userName", smsConfig.getUserName()); + // 手机号 + reqJson.put("mobile", phone); + // 发送内容(必填),不超过1000字 + reqJson.put("content", templateVal); + // 签名 MD5(userName+password+mobile+content) password为明文密码 + String signStr = JeepayKit.md5(smsConfig.getUserName() + smsConfig.getAccountPwd() + phone + templateVal, CharsetUtil.UTF_8); + reqJson.put("sign", signStr); + + // 发起请求 + String reqUrl = JeepaydxSmsConfig.getSmsUrl(JeepaydxSmsConfig.SMS_SEND); + log.info("{}请求地址[post]:{},请求参数:params={}", logPrefix, reqUrl, reqJson); + HttpResponse response = HttpRequest.post(reqUrl) + .header("Content-type", "application/json") + .charset("UTF-8") + .body(reqJson.toJSONString()) + .execute(); + log.info("{}响应结果response={}", logPrefix, response.body()); + // 判断提交状态 + JSONObject resJson = JSONObject.parseObject(response.body()); + if (resJson == null) { + throw new BizException("短信发送失败"); + } + String resultCode = resJson.getString("resultCode"); + // 1 是提交成功 + if ("1".equals(resultCode)) { + return true; + }else { + throw new BizException("短信发送失败,失败原因:" + resJson.getString("resultMsg")); + } + } catch (Exception e) { + log.info("{}短信异常:", logPrefix, e); + throw new BizException("短信发送失败"); + } + } + + + @Override + public String querySmsInfo(AbstractSmsConfig smsConfig, String bizQueryType) { + JeepaydxSmsConfig jeepaydxSmsConfig = (JeepaydxSmsConfig)smsConfig; + return this.queryBalance(jeepaydxSmsConfig); + + } + + /** 查询短信余额(条数) **/ + public String queryBalance(JeepaydxSmsConfig smsConfig){ + String logPrefix = "[计全短信余额查询]"; + try { + JSONObject reqJson = new JSONObject(); + // 用户名 + reqJson.put("userName", smsConfig.getUserName()); + // token 每次请求时可以使用时间戳或者uuid值 + String uuid = UUID.randomUUID().toString(); + reqJson.put("token", uuid); + // 签名 MD5(username+password+token) + String signStr = JeepayKit.md5(smsConfig.getUserName() + smsConfig.getAccountPwd() + uuid, CharsetUtil.UTF_8); + reqJson.put("sign", signStr); + + // 发起请求 + String reqUrl = JeepaydxSmsConfig.getSmsUrl(JeepaydxSmsConfig.SMS_BALANCE_QUERY); + log.info("{}请求地址[post]:{},请求参数:params={}", logPrefix, reqUrl, reqJson); + HttpResponse response = HttpRequest.post(reqUrl) + .header("Content-type", "application/json") + .charset("UTF-8") + .body(reqJson.toJSONString()) + .execute(); + log.info("{}响应结果response={}", logPrefix, response.body()); + // 判断提交状态 + JSONObject resJson = JSONObject.parseObject(response.body()); + if (resJson == null) { + throw new BizException("短信余额查询失败"); + } + String resultCode = resJson.getString("resultCode"); + // 1 是查询成功 + if ("1".equals(resultCode)) { + return resJson.getString("balance"); + }else { + log.info("{}查询失败,失败原因:{}", logPrefix, resJson.getString("resultMsg")); + return null; + } + } catch (Exception e) { + log.info("{}查询异常:", logPrefix, e); + return null; + } + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsHandler.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsHandler.java new file mode 100644 index 0000000..04c52a8 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsHandler.java @@ -0,0 +1,62 @@ +package com.jeequan.jeepay.core.sms; + +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.smsconfig.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class JuhedxSmsHandler implements ISmsHandler { + @Override + public void sendVercode(SmsBizVercodeModel smsBizVercodeModel, AbstractSmsConfig smsConfig) { + JuhedxSmsConfig juhedxSmsConfig = (JuhedxSmsConfig)smsConfig; + + String smsTemplateId = ""; + if (CS.SMS_TYPE_API_ENUM.TYPE_AUTH.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = juhedxSmsConfig.getLoginMchTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_REGISTER.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = juhedxSmsConfig.getRegisterMchTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_RETRIEVE.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = juhedxSmsConfig.getForgetPwdTemplateId(); + }else if (CS.SMS_TYPE_API_ENUM.TYPE_MBR_TEL_BIND.equals(smsBizVercodeModel.getSmsBizType())) { + smsTemplateId = juhedxSmsConfig.getMbrTelBindTemplateId(); + } + + // 生成短信验证码 + String verifyCode = smsBizVercodeModel.getSmsVercode(); + JSONObject codeObj = new JSONObject(); + codeObj.put("mobile", smsBizVercodeModel.getPhoneNo()); + codeObj.put("tpl_id", smsTemplateId); + codeObj.put("tpl_value", "#code#=" + verifyCode); + codeObj.put("key", juhedxSmsConfig.getAccessKeyId()); + + JuhedxSmsProcessKit.callInterface(juhedxSmsConfig, smsTemplateId, codeObj); + } + + @Override + public void sendDiyContent(SmsBizDiyContentModel smsBizDiyContentModel, AbstractSmsConfig smsConfig) { + JuhedxSmsConfig juhedxSmsConfig = (JuhedxSmsConfig) smsConfig; + String templateId = juhedxSmsConfig.getForgetPwdTemplateId(); + JSONObject codeObj = new JSONObject(); + codeObj.put("mobile", smsBizDiyContentModel.getPhoneNo()); + if(CS.SMS_TYPE_API_ENUM.TYPE_ACCOUNT_OPEN.equals(smsBizDiyContentModel.getSmsBizType())){ + codeObj.put("loginName", smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_LOGIN_NAME)); + codeObj.put("loginPwd", smsBizDiyContentModel.getString(SmsBizDiyContentModel.FIELD_USER_PWD)); + } + if(CS.SMS_TYPE_API_ENUM.TYPE_ACCOUNT_BALANCE.equals(smsBizDiyContentModel.getSmsBizType())){ + codeObj.put("tpl_value", "#name#=" + smsBizDiyContentModel.getString("name") + "&#amount#=" + smsBizDiyContentModel.getString("amount")); + templateId = juhedxSmsConfig.getAccountBalanceTemplateId(); + } + codeObj.put("key", juhedxSmsConfig.getAccessKeyId()); + codeObj.put("tpl_id", templateId); + JuhedxSmsProcessKit.callInterface(juhedxSmsConfig, templateId, codeObj); + } + + @Override + public String querySmsInfo(AbstractSmsConfig smsConfig, String bizQueryType) { + throw new BizException("聚合数据不支持该操作"); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsProcessKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsProcessKit.java new file mode 100644 index 0000000..a5702dc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/JuhedxSmsProcessKit.java @@ -0,0 +1,44 @@ +package com.jeequan.jeepay.core.sms; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.smsconfig.JuhedxSmsConfig; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import javax.servlet.ServletException; +import java.util.Map; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JuhedxSmsProcessKit { + + public static boolean callInterface(JuhedxSmsConfig smsConfig, String templateId, Map param){ + try { + if (smsConfig == null || StringUtils.isEmpty(templateId)) { + return false; + } + + String response = HttpUtil.post(JuhedxSmsConfig.getSmsUrl(JuhedxSmsConfig.SMS_SEND), param); + + if(response == null){ + throw new ServletException("短信接口异常!"); + } + + JSONObject respParam = JSON.parseObject(response); + if (JuhedxSmsConfig.SUCCESS_CODE != respParam.getIntValue("error_code")) { + throw new ServletException(respParam.getString("reason")); + } + + } catch (Exception e) { + + log.info("短信异常:", e); + throw new BizException("短信发送失败"); + } + + return true; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/MocktestSmsHandler.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/MocktestSmsHandler.java new file mode 100644 index 0000000..0eab5d1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/sms/MocktestSmsHandler.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.core.sms; + +import com.jeequan.jeepay.core.model.smsconfig.AbstractSmsConfig; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizDiyContentModel; +import com.jeequan.jeepay.core.model.smsconfig.SmsBizVercodeModel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/*** +* mocktest 短信通道 +* +* @author terrfly +* @date 2023/8/18 16:34 +*/ +@Slf4j +@Service +public class MocktestSmsHandler implements ISmsHandler { + + + @Override + public void sendVercode(SmsBizVercodeModel smsBizVercodeModel, AbstractSmsConfig smsConfig) { + + } + + @Override + public void sendDiyContent(SmsBizDiyContentModel smsBizDiyContentModel, AbstractSmsConfig smsConfig) { + + + } + + @Override + public String querySmsInfo(AbstractSmsConfig smsConfig, String bizQueryType) { + return null; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/task/XxlJobExecutorProp.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/task/XxlJobExecutorProp.java new file mode 100644 index 0000000..6640cc1 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/task/XxlJobExecutorProp.java @@ -0,0 +1,14 @@ +package com.jeequan.jeepay.core.task; + +import lombok.Data; + +@Data +public class XxlJobExecutorProp { + + private String adminAddress; + private String accessToken; + private String appname; + private Integer port; + private String logPath; + private Integer logretentiondays; +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/AmountUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/AmountUtil.java new file mode 100644 index 0000000..5f0737f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/AmountUtil.java @@ -0,0 +1,184 @@ +package com.jeequan.jeepay.core.utils; + +import java.math.BigDecimal; + +/** + * @Description: 金额工具类 + * @author dingzhiwei jmdhappy@126.com + * @date 2017-07-05 + * @version V1.0 + * @Copyright: www.xxpay.org + */ +public class AmountUtil { + + /** + * 将字符串"元"转换成"分" + * @param str + * @return + */ + public static String convertDollar2Cent(String str) { + + return Long.toString(convertDollar2CentLong(str)); + // 以下为 旧模式, 会提示: The program calls a method that parses doubles and can cause the thread to hang. 检测静态漏洞 +// DecimalFormat df = new DecimalFormat("0.00"); +// StringBuffer sb = df.format(Double.parseDouble(str), +// new StringBuffer(), new FieldPosition(0)); +// int idx = sb.toString().indexOf("."); +// sb.deleteCharAt(idx); +// for (; sb.length() != 1;) { +// if(sb.charAt(0) == '0') { +// sb.deleteCharAt(0); +// } else { +// break; +// } +// } +// return sb.toString(); + } + + /** + * 将字符串"元"转换成"分" Long类型 + * @param str + * @return + */ + public static Long convertDollar2CentLong(String str) { + return new BigDecimal(str).multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_FLOOR).longValue(); + } + + /** + * "元"转换成"分" Long类型 + * @param bigDecimal + * @return + */ + public static Long convertDollar2CentLong(BigDecimal bigDecimal) { + return bigDecimal.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_FLOOR).longValue(); + } + + /** + * 将字符串"分"转换成"元"(长格式),如:100分被转换为1.00元。 + * @param s + * @return + */ + public static String convertCent2Dollar(String s) { + if("".equals(s) || s ==null){ + return ""; + } + long l; + if(s.length() != 0) { + if(s.charAt(0) == '+') { + s = s.substring(1); + } + l = Long.parseLong(s); + } else { + return ""; + } + boolean negative = false; + if(l < 0) { + negative = true; + l = Math.abs(l); + } + s = Long.toString(l); + if(s.length() == 1) { + return(negative ? ("-0.0" + s) : ("0.0" + s)); + } + if(s.length() == 2) { + return(negative ? ("-0." + s) : ("0." + s)); + } else { + return(negative ? ("-" + s.substring(0, s.length() - 2) + "." + s + .substring(s.length() - 2)) : (s.substring(0, + s.length() - 2) + + "." + s.substring(s.length() - 2))); + } + } + + + + /** + * 将Long "分"转换成"元"(长格式),如:100分被转换为1.00元。 + * @param s + * @return + */ + public static String convertCent2Dollar(Long s){ + if(s == null) { + return ""; + } + return new BigDecimal(s).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toString(); + } + + /** + * 将字符串"分"转换成"元"(短格式),如:100分被转换为1元。 + * @param s + * @return + */ + public static String convertCent2DollarShort(String s) { + String ss = convertCent2Dollar(s); + ss = "" + Double.parseDouble(ss); + if(ss.endsWith(".0")) { + return ss.substring(0, ss.length() - 2); + } + if(ss.endsWith(".00")) { + return ss.substring(0, ss.length() - 3); + } else { + return ss; + } + } + + + /** + * 计算百分比类型的各种费用值 (订单金额 * 真实费率 结果四舍五入并保留0位小数 ) + * + * @author terrfly + * + * @date 2021/8/20 14:53 + * @param amount 订单金额 (保持与数据库的格式一致 ,单位:分) + * @param rate 费率 (保持与数据库的格式一致 ,真实费率值,如费率为0.55%,则传入 0.0055) + */ + public static Long calPercentageFee(Long amount, BigDecimal rate){ + return calPercentageFee(amount, rate, BigDecimal.ROUND_HALF_UP); + } + + /** + * 计算百分比类型的各种费用值 (订单金额 * 真实费率 结果四舍五入并保留0位小数 ) + * + * @author terrfly + * + * @date 2021/8/20 14:53 + * @param amount 订单金额 (保持与数据库的格式一致 ,单位:分) + * @param rate 费率 (保持与数据库的格式一致 ,真实费率值,如费率为0.55%,则传入 0.0055) + * @param mode 模式 参考:BigDecimal.ROUND_HALF_UP(四舍五入) BigDecimal.ROUND_FLOOR(向下取整) + */ + public static Long calPercentageFee(Long amount, BigDecimal rate, int mode){ + //费率乘以订单金额 结果四舍五入并保留0位小数 + return new BigDecimal(amount).multiply(rate).setScale(0, mode).longValue(); + } + + + /** 最小 0 **/ + public static Long minZero(Long amount){ + + if(amount == null){ + return null; + } + + return amount < 0L ? 0L : amount; + } + + + /** 美化百分比 **/ + public static String convertPercentage(BigDecimal num){ + return convertPercentage(num, 2); + } + + /** 美化百分比 **/ + public static String convertPercentage(BigDecimal num, int scale){ + return num.multiply(new BigDecimal("100")).setScale(scale, BigDecimal.ROUND_HALF_UP).toPlainString() + "%"; + } + + /** + * 取绝对值 + * @param amount + * @return + */ + public static Long abs(Long amount){ + return Math.abs(amount == null ? 0L : amount); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ApiResBodyAdviceKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ApiResBodyAdviceKit.java new file mode 100644 index 0000000..6b12d7d --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ApiResBodyAdviceKit.java @@ -0,0 +1,110 @@ +package com.jeequan.jeepay.core.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.ApiRes; +import com.jeequan.jeepay.core.model.OriginalRes; +import org.springframework.core.io.InputStreamResource; + +import java.util.Collection; + +/* + * 自定义springMVC的controller的返回值 + * 功能: + * 1. 自动添加ApiRes.ok(); + * 2. 处理model的扩展字段 (只需要在model中设置[ext]参数, 可以实现json自动转换为外层字段。 ) + * 比如 model为 {id:1, ext:{abc:222}} 则自动转换为: {id:1, abc:222} + * @author terrfly + * @date 2021/6/8 16:49 + */ +public class ApiResBodyAdviceKit { + + /** + * 扩展字段的key名称 + **/ + private static final String API_EXTEND_FIELD_NAME = "ext"; + + public static Object beforeBodyWrite(Object body) { + + //空的情况 不处理 + if (body == null) { + return null; + } + + if (body instanceof OriginalRes) { + return ((OriginalRes) body).getData(); + } + + // 返回String 避免 StringHttpMessageConverter + if (body instanceof String) { + return body; + } + + //返回文件流不处理 + if (body instanceof InputStreamResource) { + return body; + } + + //返回二进制文件不处理 + if (body instanceof byte[]) { + return body; + } + + //如果为ApiRes类型则仅处理扩展字段 + if (body instanceof ApiRes) { + return procAndConvertJSON(body); + } else { + + //ctrl返回其他非[ApiRes]认为处理成功, 先转换为成功状态, 在处理字段 + return procAndConvertJSON(ApiRes.ok(body)); + } + } + + /** + * 处理扩展字段 and 转换为json格式 + **/ + public static Object procAndConvertJSON(Object object) { + + Object json = JSON.toJSON(object); //转换为JSON格式 + + if (json instanceof JSONObject) { //对象类型 + processExtFieldByJSONObject((JSONObject) json); + return json; + } + + if (json instanceof Collection) { //数组类型 + + JSONArray result = new JSONArray(); + for (Object itemObj : (Collection) json) { + result.add(procAndConvertJSON(itemObj)); + } + return result; + } + + return json; + } + + + /** + * 处理jsonObject格式 + **/ + private static void processExtFieldByJSONObject(JSONObject jsonObject) { + + //如果包含字段, 则赋值到外层然后删除该字段 + if (jsonObject.containsKey(API_EXTEND_FIELD_NAME)) { + JSONObject exFieldMap = jsonObject.getJSONObject(API_EXTEND_FIELD_NAME); + if (exFieldMap != null) { //包含字段 + for (String s : exFieldMap.keySet()) { //遍历赋值到外层 + jsonObject.put(s, exFieldMap.get(s)); + } + } + jsonObject.remove(API_EXTEND_FIELD_NAME); //删除字段 + } + + //处理所有值 + for (String key : jsonObject.keySet()) { + jsonObject.put(key, procAndConvertJSON(jsonObject.get(key))); + } + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/Base64.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/Base64.java new file mode 100644 index 0000000..bb1784e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/Base64.java @@ -0,0 +1,455 @@ +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jeequan.jeepay.core.utils; + +import java.nio.charset.StandardCharsets; + +/** + * Provides Base64 encoding and decoding as defined by RFC 2045. + * + *

This class implements section 6.8. Base64 Content-Transfer-Encoding + * from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and + * Borenstein.

+ * + * @author Apache Software Foundation + * @version $Id: Base64.java,v 1.20 2004/05/24 00:21:24 ggregory Exp $ + * @see RFC 2045 + * @since 1.0-dev + */ +public class Base64 { + + /** + * Chunk size per RFC 2045 section 6.8. + * + *

The {@value} character limit does not count the trailing CRLF, but counts + * all other characters, including any equal signs.

+ * + * @see RFC 2045 section 6.8 + */ + static final int CHUNK_SIZE = 76; + + /** + * Chunk separator per RFC 2045 section 2.1. + * + * @see RFC 2045 section 2.1 + */ + static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); + + /** + * The base length. + */ + static final int BASELENGTH = 255; + + /** + * Lookup length. + */ + static final int LOOKUPLENGTH = 64; + + /** + * Used to calculate the number of bits in a byte. + */ + static final int EIGHTBIT = 8; + + /** + * Used when encoding something which has fewer than 24 bits. + */ + static final int SIXTEENBIT = 16; + + /** + * Used to determine how many bits data contains. + */ + static final int TWENTYFOURBITGROUP = 24; + + /** + * Used to get the number of Quadruples. + */ + static final int FOURBYTE = 4; + + /** + * Used to test the sign of a byte. + */ + static final int SIGN = -128; + + /** + * Byte used to pad output. + */ + static final byte PAD = (byte) '='; + + // Create arrays to hold the base64 characters and a + // lookup for base64 chars + private static byte[] base64Alphabet = new byte[BASELENGTH]; + private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; + + // Populating the lookup and character arrays + static { + for (int i = 0; i < BASELENGTH; i++) { + base64Alphabet[i] = (byte) -1; + } + for (int i = 'Z'; i >= 'A'; i--) { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i >= 'a'; i--) { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + for (int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++) { + lookUpBase64Alphabet[i] = (byte) ('A' + i); + } + + for (int i = 26, j = 0; i <= 51; i++, j++) { + lookUpBase64Alphabet[i] = (byte) ('a' + j); + } + + for (int i = 52, j = 0; i <= 61; i++, j++) { + lookUpBase64Alphabet[i] = (byte) ('0' + j); + } + + lookUpBase64Alphabet[62] = (byte) '+'; + lookUpBase64Alphabet[63] = (byte) '/'; + } + + private static boolean isBase64(byte octect) { + if (octect == PAD) { + return true; + } else if (base64Alphabet[octect] == -1) { + return false; + } else { + return true; + } + } + + /** + * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. + * + * @param arrayOctect byte array to test + * @return true if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; false, otherwise + */ + public static boolean isArrayByteBase64(byte[] arrayOctect) { + + arrayOctect = discardWhitespace(arrayOctect); + + int length = arrayOctect.length; + if (length == 0) { + // shouldn't a 0 length array be valid base64 data? + // return false; + return true; + } + for (int i = 0; i < length; i++) { + if (!isBase64(arrayOctect[i])) { + return false; + } + } + return true; + } + + /** + * Encodes binary data using the base64 algorithm but does not chunk the output. + * + * @param binaryData binary data to encode + * @return Base64 characters + */ + public static byte[] encodeBase64(byte[] binaryData) { + return encodeBase64(binaryData, false); + } + + /** + * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks + * + * @param binaryData binary data to encode + * @return Base64 characters chunked in 76 character blocks + */ + public static byte[] encodeBase64Chunked(byte[] binaryData) { + return encodeBase64(binaryData, true); + } + + /** + * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. + * + * @param binaryData Array containing binary data to encode. + * @param isChunked if isChunked is true this encoder will chunk the base64 output into 76 character blocks + * @return Base64-encoded data. + */ + public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { + int lengthDataBits = binaryData.length * EIGHTBIT; + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + byte encodedData[] = null; + int encodedDataLength = 0; + int nbrChunks = 0; + + if (fewerThan24bits != 0) { + //data not divisible by 24 bit + encodedDataLength = (numberTriplets + 1) * 4; + } else { + // 16 or 8 bit + encodedDataLength = numberTriplets * 4; + } + + // If the output is to be "chunked" into 76 character sections, + // for compliance with RFC 2045 MIME, then it is important to + // allow for extra length to account for the separator(s) + if (isChunked) { + + nbrChunks = + (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE)); + encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; + } + + encodedData = new byte[encodedDataLength]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + int i = 0; + int nextSeparatorIndex = CHUNK_SIZE; + int chunksSoFar = 0; + + //log.debug("number of triplets = " + numberTriplets); + for (i = 0; i < numberTriplets; i++) { + dataIndex = i * 3; + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + b3 = binaryData[dataIndex + 2]; + + //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3); + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = + ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = + ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = + ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; + //log.debug( "val2 = " + val2 ); + //log.debug( "k4 = " + (k<<4) ); + //log.debug( "vak = " + (val2 | (k<<4)) ); + encodedData[encodedIndex + 1] = + lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex + 2] = + lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; + + encodedIndex += 4; + + // If we are chunking, let's put a chunk separator down. + if (isChunked) { + // this assumes that CHUNK_SIZE % 4 == 0 + if (encodedIndex == nextSeparatorIndex) { + System.arraycopy( + CHUNK_SEPARATOR, + 0, + encodedData, + encodedIndex, + CHUNK_SEPARATOR.length); + chunksSoFar++; + nextSeparatorIndex = + (CHUNK_SIZE * (chunksSoFar + 1)) + + (chunksSoFar * CHUNK_SEPARATOR.length); + encodedIndex += CHUNK_SEPARATOR.length; + } + } + } + + // form integral number of 6-bit groups + dataIndex = i * 3; + + if (fewerThan24bits == EIGHTBIT) { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + //log.debug("b1=" + b1); + //log.debug("b1<<2 = " + (b1>>2) ); + byte val1 = + ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex + 2] = PAD; + encodedData[encodedIndex + 3] = PAD; + } else if (fewerThan24bits == SIXTEENBIT) { + + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = + ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = + ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex + 1] = + lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex + 3] = PAD; + } + + if (isChunked) { + // we also add a separator to the end of the final chunk. + if (chunksSoFar < nbrChunks) { + System.arraycopy( + CHUNK_SEPARATOR, + 0, + encodedData, + encodedDataLength - CHUNK_SEPARATOR.length, + CHUNK_SEPARATOR.length); + } + } + + return encodedData; + } + + /** + * Decodes Base64 data into octects + * + * @param base64Data Byte array containing Base64 data + * @return Array containing decoded data. + */ + public static byte[] decodeBase64(byte[] base64Data) { + // RFC 2045 requires that we discard ALL non-Base64 characters + base64Data = discardNonBase64(base64Data); + + // handle the edge case, so we don't have to worry about it later + if (base64Data.length == 0) { + return new byte[0]; + } + + int numberQuadruple = base64Data.length / FOURBYTE; + byte decodedData[] = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; + + // Throw away anything not in base64Data + + int encodedIndex = 0; + int dataIndex = 0; + { + // this sizes the output array properly - rlw + int lastData = base64Data.length; + // ignore the '=' padding + while (base64Data[lastData - 1] == PAD) { + if (--lastData == 0) { + return new byte[0]; + } + } + decodedData = new byte[lastData - numberQuadruple]; + } + + for (int i = 0; i < numberQuadruple; i++) { + dataIndex = i * 4; + marker0 = base64Data[dataIndex + 2]; + marker1 = base64Data[dataIndex + 3]; + + b1 = base64Alphabet[base64Data[dataIndex]]; + b2 = base64Alphabet[base64Data[dataIndex + 1]]; + + if (marker0 != PAD && marker1 != PAD) { + //No PAD e.g 3cQl + b3 = base64Alphabet[marker0]; + b4 = base64Alphabet[marker1]; + + decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex + 1] = + (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); + } else if (marker0 == PAD) { + //Two PAD e.g. 3c[Pad][Pad] + decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + } else if (marker1 == PAD) { + //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[marker0]; + + decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex + 1] = + (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + } + encodedIndex += 3; + } + return decodedData; + } + + /** + * Discards any whitespace from a base-64 encoded block. + * + * @param data The base-64 encoded data to discard the whitespace from. + * @return The data, less whitespace (see RFC 2045). + */ + static byte[] discardWhitespace(byte[] data) { + byte groomedData[] = new byte[data.length]; + int bytesCopied = 0; + + for (int i = 0; i < data.length; i++) { + switch (data[i]) { + case (byte) ' ': + case (byte) '\n': + case (byte) '\r': + case (byte) '\t': + break; + default: + groomedData[bytesCopied++] = data[i]; + } + } + + byte packedData[] = new byte[bytesCopied]; + + System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); + + return packedData; + } + + /** + * Discards any characters outside of the base64 alphabet, per the requirements on page 25 of RFC 2045 - "Any characters outside of the + * base64 alphabet are to be ignored in base64 encoded data." + * + * @param data The base-64 encoded data to groom + * @return The data, less non-base64 characters (see RFC 2045). + */ + static byte[] discardNonBase64(byte[] data) { + byte groomedData[] = new byte[data.length]; + int bytesCopied = 0; + + for (int i = 0; i < data.length; i++) { + if (isBase64(data[i])) { + groomedData[bytesCopied++] = data[i]; + } + } + + byte packedData[] = new byte[bytesCopied]; + + System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); + + return packedData; + } + + + + public static String encodeBase64String(byte[] input) { + return new String(encodeBase64(input), StandardCharsets.UTF_8); + } + + public static byte[] decodeBase64String(String base64String) { + return Base64.decodeBase64(base64String.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/DateKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/DateKit.java new file mode 100644 index 0000000..c7efb5f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/DateKit.java @@ -0,0 +1,139 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.SystemClock; +import com.jeequan.jeepay.core.exception.BizException; +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; + +/* +* 时间工具类 +* +* @author terrfly +* +* @date 2021/6/8 16:58 +*/ +public class DateKit { + + /** 获取参数时间当天的开始时间 **/ + public static Date getBegin(Date date){ + + if(date == null) { + return null; + } + return DateUtil.beginOfDay(date).toJdkDate(); + } + + /** 获取参数时间当天的结束时间 **/ + public static Date getEnd(Date date){ + if(date == null) { + return null; + } + return DateUtil.endOfDay(date).toJdkDate(); + } + + + /** + * 获取自定义查询时间 + * today -- 今天 + * yesterday -- 昨天 + * near2now_7 -- 近xx天, 到今天 + * near2yesterday_30 -- 近xx天, 到昨天 + * customDate_2020-01-01_N -- 自定义日期格式 N表示为空, 占位使用, 自动拼接 00:00:00 和 23:59:59 + * customDateTime_2020-01-01 23:00:00_2020-01-01 23:00:00 -- 自定义日期时间格式 + * + * @return + */ + public static Date[] getQueryDateRange(String queryParamVal){ + + //查询全部 + if(StringUtils.isEmpty(queryParamVal)){ + return new Date[]{null, null}; + } + + Date nowDateTime = new Date(); //当前时间 + + if("today".equals(queryParamVal)){ //今天 + return new Date[]{getBegin(nowDateTime), getEnd(nowDateTime)}; + + }else if("toweek".equals(queryParamVal)){ //本周 + return new Date[]{getBegin(DateUtil.beginOfWeek(nowDateTime)), getEnd(DateUtil.endOfWeek(nowDateTime))}; + + }else if("yesterday".equals(queryParamVal)){ //昨天 + + Date yesterdayDateTime = DateUtil.offsetDay(nowDateTime, -1).toJdkDate(); //昨天 + return new Date[]{getBegin(yesterdayDateTime), getEnd(yesterdayDateTime)}; + + }else if("currMonth".equals(queryParamVal)){ // 本月 + + return new Date[]{ DateUtil.beginOfMonth(nowDateTime), DateUtil.endOfMonth(nowDateTime) }; + + }else if("prevMonth".equals(queryParamVal)){ // 上月 + + return new Date[]{ DateUtil.beginOfMonth(DateUtil.lastMonth()), DateUtil.endOfMonth(DateUtil.lastMonth()) }; + + } + + //根据 _ 分割 + String[] valArray = queryParamVal.split("_"); + + String dateType = valArray[0]; //时间类型 + + if("near2now".equals(dateType)){ //近xx天, xx天之前 ~ 当前时间 + + if(valArray.length != 2){ //参数有误 + throw new BizException("查询时间参数有误"); + } + String dateVal = valArray[1]; //搜索时间值 + + Integer offsetDay = 1 - Integer.parseInt(dateVal); //获取时间偏移量 + Date offsetDayDate = DateUtil.offsetDay(nowDateTime, offsetDay).toJdkDate(); + return new Date[]{getBegin(offsetDayDate), getEnd(nowDateTime)}; + + }else if("near2yesterday".equals(dateType)){ //近xx天, xx天之前 ~ 昨天 + + if(valArray.length != 2){ //参数有误 + throw new BizException("查询时间参数有误"); + } + String dateVal = valArray[1]; //搜索时间值 + + Date yesterdayDateTime = DateUtil.offsetDay(nowDateTime, -1).toJdkDate(); //昨天 + + Integer offsetDay = 1 - Integer.parseInt(dateVal); //获取时间偏移量 + Date offsetDayDate = DateUtil.offsetDay(yesterdayDateTime, offsetDay).toJdkDate(); + return new Date[]{getBegin(offsetDayDate), getEnd(yesterdayDateTime)}; + + }else if("customDate".equals(dateType) || "customDateTime".equals(dateType)){ //自定义格式 + + if(valArray.length != 3){ //参数有误 + throw new BizException("查询时间参数有误"); + } + + String timeStr1 = "N".equalsIgnoreCase(valArray[1]) ? null : valArray[1] ; //开始时间, + String timeStr2 = "N".equalsIgnoreCase(valArray[2]) ? null : valArray[2]; //结束时间, N表示为空, 占位使用 + + Date time1 = null; + Date time2 = null; + + if(StringUtils.isNotEmpty(timeStr1)){ + time1 = DateUtil.parseDateTime("customDate".equals(dateType) ? (timeStr1 + " 00:00:00" ) : timeStr1); + } + if(StringUtils.isNotEmpty(timeStr2)){ + time2 = DateUtil.parse( ( "customDate".equals(dateType) ? (timeStr2 + " 23:59:59.999" ) : timeStr2 + ".999" ) , DatePattern.NORM_DATETIME_MS_FORMAT); + } + return new Date[]{time1, time2}; + + }else{ + throw new BizException("查询时间参数有误"); + } + } + + /** 公共函数,获取当前时间。 **/ + public static Long currentTimeMillis(){ +// System.currentTimeMillis(); // fortify 检测属于安全漏洞 + return SystemClock.now(); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ExcelUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ExcelUtil.java new file mode 100644 index 0000000..52baa05 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ExcelUtil.java @@ -0,0 +1,121 @@ +package com.jeequan.jeepay.core.utils; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.csv.CsvData; +import cn.hutool.core.text.csv.CsvUtil; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.poi.ss.usermodel.Workbook; + +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * 导出EXCEL util + * + * @author xiaoyu + * + * @date 2022/1/12 18:02 + */ +public class ExcelUtil { + + + /** + * excel 导出 + * + * @param list 数据列表 + * @param pojoClass pojo类型 + * @param fileName 导出时的excel名称 + * @param response + * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) + */ + private static void defaultExport(List list, Class pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException { + //把数据添加到excel表格中 + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); + downLoadExcel(fileName, response, workbook); + } + + /** + * excel 导出 + * + * @param list 数据列表 + * @param title 表格内数据标题 + * @param sheetName sheet名称 + * @param pojoClass pojo类型 + * @param fileName 导出时的excel名称 + * @param response + */ + public static void exportExcel(List list, String title, String sheetName, Class pojoClass, String fileName, HttpServletResponse response) throws IOException { + defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF)); + } + + /** + * excel下载 + * + * @param fileName 下载时的文件名称 + * @param response + * @param workbook excel数据 + */ + private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException { + try { + response.setCharacterEncoding("UTF-8"); + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8")); + workbook.write(response.getOutputStream()); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + + + /** + * 功能描述: 通过inputStream解压Zip 并读取csv文件 + * + * @param inputStream + * @param zipFileNameCharset + * @param inputStreamReaderCharset + * @Return: csv集合 + * @Author: terrfly + * @Date: 2022/10/27 10:04 + */ + public static List> readCsvDataByZipInputStream(InputStream inputStream, Charset zipFileNameCharset, Charset inputStreamReaderCharset) throws IOException { + + List> result = new ArrayList<>(); + + ZipInputStream zipInputStream = new ZipInputStream(inputStream, zipFileNameCharset); + ZipEntry zipEntry = zipInputStream.getNextEntry(); + while (zipEntry != null) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + IoUtil.copy(zipInputStream, byteArrayOutputStream); + + CsvData csvData = CsvUtil.getReader(new InputStreamReader(IoUtil.toStream(byteArrayOutputStream), inputStreamReaderCharset)).read(); + result.add(MutablePair.of(zipEntry, csvData)); + zipEntry = zipInputStream.getNextEntry(); + } + + return result; + } + + /** + * 读取csv文件内容 + * @param outputStream + * @param inputStreamReaderCharset + * @return + */ + public static CsvData readCsvData(ByteArrayOutputStream outputStream, Charset inputStreamReaderCharset) { + CsvData csvData = CsvUtil.getReader(new InputStreamReader(IoUtil.toStream(outputStream), inputStreamReaderCharset)).read(); + return csvData; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/FileKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/FileKit.java new file mode 100644 index 0000000..0a99335 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/FileKit.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.core.utils; + +/* +* 文件工具类 +* +* @author terrfly +* +* @date 2021/6/8 16:50 +*/ +public class FileKit { + + + /** + * 获取文件的后缀名 + * @param appendDot 是否拼接. + * @return + */ + public static String getFileSuffix(String fullFileName, boolean appendDot){ + if(fullFileName == null || fullFileName.indexOf(".") < 0 || fullFileName.length() <= 1) { + return ""; + } + return (appendDot? "." : "") + fullFileName.substring(fullFileName.lastIndexOf(".") + 1); + } + + + /** 获取URL中最后的文件名称, 包含后缀 **/ + public static String getUrlFileName(String url){ + return url.substring(url.lastIndexOf("/") + 1); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/HolidayUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/HolidayUtil.java new file mode 100644 index 0000000..4dfa66f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/HolidayUtil.java @@ -0,0 +1,106 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * TODO + * 节假日工具类型 + * @author crystal + * @date 2024/3/7 17:04 + */ +@Slf4j +public class HolidayUtil { + + public static final int SUCCESS = 0; + + /** + * 接口请求地址 + */ + public static final String url = "https://timor.tech/api/holiday/info/"; + + + /** + * 判断日期是否是节假日 + * "type": enum(0, 1, 2, 3), / 节假日类型,分别表示 工作日、周末、节日、调休。 + * @param date + * @return false 表示工作日 true 表示节假日 节日或者是周末 + * {"code":0,"type":{"type":0,"name":"周一","week":1},"holiday":null} + * { + * "code": 0, + * "type": { + * "type": 2, + * "name": "劳动节", + * "week": 3 + * }, + * "holiday": { + * "holiday": true, + * "name": "劳动节", + * "wage": 3, + * "date": "2024-05-01", + * "rest": 24 + * } + * } + */ + public static boolean isWorkDay(Date date) { + String queryDate = DateUtil.formatDate(date); + String reqUrl = url + queryDate; + HttpResponse response = HttpRequest.get(reqUrl).execute(); + if(!response.isOk()){ + throw new BizException("节假日接口请求异常"); + } + JSONObject body = JSON.parseObject(response.body()); + log.info("节假日接口返回参数:{}", body); + + JSONObject typeInfo = body.getJSONObject("type"); + String type = typeInfo.getString("type"); + + return "0".equals(type) || "3".equals(type); + } + + public static List getSettleDate(Date date){ + List dateList = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + String queryDate = DateUtil.formatDate(DateUtil.offsetDay(date,-i)); + String reqUrl = url + queryDate; + HttpResponse response = HttpRequest.get(reqUrl).execute(); + if(!response.isOk()){ + throw new BizException("节假日接口请求异常"); + } + JSONObject body = JSON.parseObject(response.body()); + log.info("接口返回参数:{}",body); + if(body.getIntValue("code") != SUCCESS){ + throw new BizException("服务器异常"); + } + JSONObject type = body.getJSONObject("type"); + int typeValue = type.getIntValue("type"); + //如果当前为节假日 则直接不返回数据 + if((typeValue == 1 || typeValue == 2) && i == 0){ + break; + } + if((typeValue == 1 || typeValue == 2) && i > 0){ + continue; + } + if(dateList.size() < 2){ + if(dateList.isEmpty()){ + queryDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(queryDate),-1)); + } + dateList.add(queryDate); + }else{ + break; + } + } + Collections.sort(dateList); + return dateList; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ImageUtils.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ImageUtils.java new file mode 100644 index 0000000..1c94f2f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ImageUtils.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.URLUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URL; + +/** + * 图片处理工具类 + * + * @author ruoyi + */ +public class ImageUtils { + private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); + + public static ByteArrayOutputStream compressNetPic(String url, int size) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + float scale; + try { + long contentLength = URLUtil.getContentLength(new URL(url)); + scale = ((float) size) / contentLength; + + if (scale > 1f) { + byte[] bytes = IoUtil.readBytes(URLUtil.getStream(new URL(url))); + baos.write(bytes); + return baos; + } + + ImgUtil.scale(URLUtil.getStream(new URL(url)), baos, scale); + } catch (IOException e) { + throw new IORuntimeException(e); + } + + return baos; + } + + public static void compressNetPic(String url, int size, File file) { + FileOutputStream fos; + try { + fos = new FileOutputStream(file); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + + float scale; + + try { + URL url2 = new URL(url); + long contentLength = URLUtil.getContentLength(url2); + scale = ((float) size) / contentLength; + + if (scale > 1f) { + scale = 1f; + } + + ImgUtil.scale(URLUtil.getStream(url2), fos, scale); + fos.flush(); + fos.close(); + } catch (IOException e) { + throw new IORuntimeException(e); + } + } + + /** + * 图片等比例处理 + * + * @param file + * @return + */ + public static InputStream compressScalePic(MultipartFile file) { +// float scale = scale(file.getSize()); + try { + InputStream inputStream = file.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(file.getBytes().length); + ImgUtil.scale(inputStream, outputStream, 0.8f); + return inputStream; + } catch (IOException e) { + e.printStackTrace(); + log.error("图片压缩失败"); + } + return null; + } + + public static float scale(long srcSize) { + float scale = 0f; + if (srcSize < 200 * 1000) { + scale = 1.00f; + } else if (srcSize < 500 * 1000) { + scale = 0.57f; + } else if (srcSize < 700 * 1000) { + scale = 0.47f; + } else if (srcSize < 1 * 1000 * 1000) { + scale = 0.37f; + } else if (srcSize < 2 * 1000 * 1000) { + scale = 0.25f; + } else if (srcSize < 4 * 1000 * 1000) { + scale = 0.17f; + } else if (srcSize < 5 * 1000 * 1000) { + scale = 0.13f; + } else if (srcSize < 10 * 1000 * 1000) { + scale = 0.10f; + } else { + scale = 0.05f; + } + return scale; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/InviteCodeUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/InviteCodeUtil.java new file mode 100644 index 0000000..14e11af --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/InviteCodeUtil.java @@ -0,0 +1,132 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.util.RandomUtil; + +import java.security.SecureRandom; +import java.util.Random; + +/** + * 邀请码生成器,基本原理:
+ * 1)入参用户ID:1
+ * 2)使用自定义进制转换之后为:V
+ * 3)转换未字符串,并在后面添加'A':VA
+ * 4)在VA后面再随机补足4位,得到:VAHKHE
+ * 5)反向转换时以'A'为分界线,'A'后面的不再解析
+ * + * @author zx + */ +public class InviteCodeUtil { + + /** + * 自定义进制(0,1没有加入,容易与o,l混淆),数组顺序可进行调整增加反推难度,A用来补位因此此数组不包含A,共31个字符。 + */ + private static final char[] BASE = new char[]{'H', 'F', 'E', '8', 'S', '2', 'D', 'Z', 'X', '9', 'C', '7', 'P', + '5', 'K', '3', 'M', 'J', 'U', 'N', 'R', '4', 'W', 'Y', 'L', 'T', 'V', '6', 'B', 'G', 'Q'}; + + /** + * A补位字符,不能与自定义重复 + */ + private static final char SUFFIX_CHAR = 'A'; + + /** + * 进制长度 + */ + private static final int BIN_LEN = BASE.length; + + /** + * 生成邀请码最小长度 + */ + private static final int CODE_LEN = 6; + + /** + * ID转换为邀请码 + * + * @param id + * @return + */ + public static String idToCode(Long id) { + char[] buf = new char[BIN_LEN]; + int charPos = BIN_LEN; + + // 当id除以数组长度结果大于0,则进行取模操作,并以取模的值作为数组的坐标获得对应的字符 + while (id / BIN_LEN > 0) { + int index = (int) (id % BIN_LEN); + buf[--charPos] = BASE[index]; + id /= BIN_LEN; + } + + buf[--charPos] = BASE[(int) (id % BIN_LEN)]; + // 将字符数组转化为字符串 + String result = new String(buf, charPos, BIN_LEN - charPos); + + // 长度不足指定长度则随机补全 + int len = result.length(); + if (len < CODE_LEN) { + StringBuilder sb = new StringBuilder(); + sb.append(SUFFIX_CHAR); + SecureRandom random = RandomUtil.getSecureRandom(); + // 去除SUFFIX_CHAR本身占位之后需要补齐的位数 + for (int i = 0; i < CODE_LEN - len - 1; i++) { + sb.append(BASE[random.nextInt(BIN_LEN)]); + } + + result += sb.toString(); + } + + return result; + } + + /** + * 邀请码解析出ID
+ * 基本操作思路恰好与idToCode反向操作。 + * + * @param code + * @return + */ + public static Long codeToId(String code) { + char[] charArray = code.toCharArray(); + long result = 0L; + for (int i = 0; i < charArray.length; i++) { + int index = 0; + for (int j = 0; j < BIN_LEN; j++) { + if (charArray[i] == BASE[j]) { + index = j; + break; + } + } + + if (charArray[i] == SUFFIX_CHAR) { + break; + } + + if (i > 0) { + result = result * BIN_LEN + index; + } else { + result = index; + } + } + + return result; + + } + + public static void main(String[] args) { + String code = idToCode(801L); + String code2 = idToCode(2L); + String code3 = idToCode(11L); + String code4 = idToCode(12L); + String code5 = idToCode(100L); + String code6 = idToCode(1000L); + String code7 = idToCode(1000000L); + String code8 = idToCode(10000000L); + System.out.println(code); + System.out.println(code2); + System.out.println(code3); + System.out.println(code4); + System.out.println(code5); + System.out.println(code6); + System.out.println(code7); + System.out.println(code8); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayKit.java new file mode 100644 index 0000000..0a80afd --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayKit.java @@ -0,0 +1,247 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.crypto.SecureUtil; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/* + * jeepay工具类 + * + * @author terrfly + * + * @date 2021/6/8 16:50 + */ +@Slf4j +public class JeepayKit { + + public static byte[] AES_KEY = "4ChT08phkz59hquD795X7w==".getBytes(); + public static String MBR_ACCOUNT_SAFE_KEY = "jRavptkL3YVOOrUqZsRuBnkaHjXHvcor"; + + /** + * 参数前缀 + */ + public static String TOKEN_KEY = "tk"; + + /** + * 加密 + **/ + public static String aesEncode(String str) { + return SecureUtil.aes(JeepayKit.AES_KEY).encryptHex(str); + } + + public static String aesDecode(String str) { + return SecureUtil.aes(JeepayKit.AES_KEY).decryptStr(str); + } + + private static String encodingCharset = "UTF-8"; + + + /** + * 获取签名串 + * + * @param map + * @return urlParam.append(key).append(" = ").append(paraMap.get ( key) == null ? "" : paraMap.get(key) ); + */ + public static String getStrSort(Map map) { + ArrayList list = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + if (null != entry.getValue() && !"".equals(entry.getValue())) { + list.add(entry.getKey() + "=" + entry.getValue() + "&"); + } + } + int size = list.size(); + String[] arrayToSort = list.toArray(new String[size]); + Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + sb.append(arrayToSort[i]); + } + return sb.substring(0, sb.length() - 1); + } + + /** + *

Description: 计算签名摘要 + *

2018年9月30日 上午11:32:46 + * + * @param map 参数Map + * @param key 商户秘钥 + * @return + */ + public static String getSign(Map map, String key) { + ArrayList list = new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + if (null != entry.getValue() && !"".equals(entry.getValue())) { + list.add(entry.getKey() + "=" + entry.getValue() + "&"); + } + } + int size = list.size(); + String[] arrayToSort = list.toArray(new String[size]); + Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + sb.append(arrayToSort[i]); + } + String result = sb.toString(); + result += "key=" + key; + log.info("signStr:{}", result); + result = md5(result, encodingCharset).toUpperCase(); + log.info("sign:{}", result); + return result; + } + + + /** + *

Description: MD5 + *

2018年9月30日 上午11:33:19 + * + * @param value + * @param charset + * @return + */ + public static String md5(String value, String charset) { + MessageDigest md = null; + try { + byte[] data = value.getBytes(charset); + md = MessageDigest.getInstance("MD5"); + byte[] digestData = md.digest(data); + return toHex(digestData); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + public static String toHex(byte input[]) { + if (input == null) { + return null; + } + StringBuffer output = new StringBuffer(input.length * 2); + for (int i = 0; i < input.length; i++) { + int current = input[i] & 0xff; + if (current < 16) { + output.append("0"); + } + output.append(Integer.toString(current, 16)); + } + + return output.toString(); + } + + /** + * map 转换为 url参数 + **/ + public static String genUrlParams(Map paraMap) { + if (paraMap == null || paraMap.isEmpty()) { + return ""; + } + StringBuffer urlParam = new StringBuffer(); + Set keySet = paraMap.keySet(); + int i = 0; + for (String key : keySet) { + urlParam.append(key).append("=").append(paraMap.get(key) == null ? "" : doEncode(paraMap.get(key).toString())); + if (++i == keySet.size()) { + break; + } + urlParam.append("&"); + } + return urlParam.toString(); + } + + static String doEncode(String str) { + if (str.contains("+")) { + try { + return URLEncoder.encode(str, "utf-8"); + } catch (Exception e) { + return null; + } + } + return str; + } + + /** + * 校验微信/支付宝二维码是否符合规范, 并根据支付类型返回对应的支付方式 + **/ + public static String getPayWayCodeByBarCode(String barCode) { + + if (StringUtils.isEmpty(barCode)) { + throw new BizException("条码为空"); + } + + //微信 : 用户付款码条形码规则:18位纯数字,以10、11、12、13、14、15开头 + //文档: https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1 + if (barCode.length() == 18 && Pattern.matches("^(10|11|12|13|14|15)(.*)", barCode)) { + return CS.PAY_WAY_CODE.WX_BAR; + } + //支付宝: 25~30开头的长度为16~24位的数字 + //文档: https://docs.open.alipay.com/api_1/alipay.trade.pay/ + else if (barCode.length() >= 16 && barCode.length() <= 24 && Pattern.matches("^(25|26|27|28|29|30)(.*)", barCode)) { + return CS.PAY_WAY_CODE.ALI_BAR; + } + //云闪付: 二维码标准: 19位 + 62开头 + //文档:https://wenku.baidu.com/view/b2eddcd09a89680203d8ce2f0066f5335a8167fa.html + else if (barCode.length() == 19 && Pattern.matches("^(62)(.*)", barCode)) { + return CS.PAY_WAY_CODE.YSF_BAR; + } + //数字人民币:01开头 + //文档:https://paas.tianquetech.com/docs/#/api/bs + else if (barCode.length() == 19 && Pattern.matches("^(01)(.*)", barCode)) { + return CS.PAY_WAY_CODE.DCEP_BAR; + } else { //暂时不支持的条码类型 + throw new BizException("不支持的条码"); + } + } + + /** + * 生成账户数据保护 签名数据(根据数据库对象) + */ + public static String genAccountSafeKey(String mbrId, Long balance) { + StringBuffer signStr = new StringBuffer(); + signStr.append(mbrId).append("_"); + signStr.append(balance).append("_"); + return md5(signStr.append(MBR_ACCOUNT_SAFE_KEY).toString(), CharsetUtil.UTF_8); + } + + /** + * 支付接口克隆,调用三方接口时ifCode处理 + * 传入原始或克隆 ifCode或ifCode_1 + * 返回的是 原始ifCode + */ + public static String getIfCodeOrigin(String ifCdoe) { + if (StringUtils.isNotBlank(ifCdoe) && ifCdoe.contains("_")) { + return ifCdoe.split("_")[0]; + } + + return ifCdoe; + } + + /** + * 微信支付目录配置判断 + **/ + public static String configPayUrlConvert(String payUrl) { + if (StringUtils.isEmpty(payUrl)) return payUrl; + // 截取末尾字符串判断 + String lastStr = payUrl.substring(payUrl.length() - 1); + if ("/".equals(lastStr)) { + return payUrl; + } else { + return payUrl + "/"; + } + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayRSA2Kit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayRSA2Kit.java new file mode 100644 index 0000000..797e8d3 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JeepayRSA2Kit.java @@ -0,0 +1,85 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.crypto.SignUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.crypto.asymmetric.SignAlgorithm; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Map; + +/*** +* RSA2 签名(参考alipay-sdk) +* +* @author terrfly +* +* @date 2022/5/17 18:04 +*/ +@Slf4j +public class JeepayRSA2Kit { + + private static final int DEFAULT_BUFFER_SIZE = 8192; + public static final String CHARSET_UTF8 = "UTF-8"; + public static final String SIGN_TYPE_RSA = "RSA"; + public static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; + + private static void io(Reader in, Writer out) throws IOException { + + char[] buffer = new char[( DEFAULT_BUFFER_SIZE >> 1 )]; + int amount; + + while ((amount = in.read(buffer)) >= 0) { + out.write(buffer, 0, amount); + } + } + + private static String readText(InputStream ins) throws IOException { + Reader reader = new InputStreamReader(ins); + StringWriter writer = new StringWriter(); + + io(reader, writer); + + return writer.toString(); + } + + private static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception { + KeyFactory keyFactory = KeyFactory.getInstance(algorithm); + + StringWriter writer = new StringWriter(); + io(new InputStreamReader(ins), writer); + + byte[] encodedKey = writer.toString().getBytes(); + + encodedKey = Base64.decodeBase64(encodedKey); + + return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + } + + /** 签名 */ + public static String getSign(Map params, String privateKey) throws Exception { + return getSign(JeepayKit.getStrSort(params), privateKey); + } + + /** 签名 */ + public static String getSign(String content, String privateKey) throws Exception { + Sign sign = SignUtil.sign(SignAlgorithm.SHA1withRSA, privateKey, null); + return new String(Base64.encodeBase64(sign.sign(content))); + } + + /** 验签 **/ + public static boolean verify(JSONObject params, String publicKey, String sign) throws Exception { + return verify(JeepayKit.getStrSort(params), publicKey, sign); + } + + /** 验签 **/ + public static boolean verify(String content, String publicKey, String signStr) throws Exception { + Sign sign = SignUtil.sign(SignAlgorithm.SHA1withRSA, null, publicKey); + log.info("加签原串:{}", content); + return sign.verify(content.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(signStr.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JsonKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JsonKit.java new file mode 100644 index 0000000..2fa0b4f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/JsonKit.java @@ -0,0 +1,22 @@ +package com.jeequan.jeepay.core.utils; + +import com.alibaba.fastjson.JSONObject; + +/* +* json工具类 +* +* @author terrfly +* +* @date 2021/6/8 16:51 +*/ +public class JsonKit { + + public static JSONObject newJson(String key, Object val){ + + JSONObject result = new JSONObject(); + result.put(key, val); + return result; + } + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/RegKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/RegKit.java new file mode 100644 index 0000000..87e5608 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/RegKit.java @@ -0,0 +1,41 @@ +package com.jeequan.jeepay.core.utils; + +/* +* +* 正则验证kit +* @author terrfly +* +* @date 2021/6/8 16:56 +*/ +public class RegKit { + + public static final String REG_MOBILE = "^1\\d{10}$"; //判断是否是手机号 + public static final String REG_ALIPAY_USER_ID = "^2088\\d{12}$"; //判断是支付宝用户Id 以2088开头的纯16位数字 + public static final String REG_NUMBER = "^\\d+$"; //数字类型 + + public static boolean isMobile(String str){ + return match(str, REG_MOBILE); + } + + public static boolean isAlipayUserId(String str){ + return match(str, REG_ALIPAY_USER_ID); + } + + public static boolean isNumber(String str){ + return match(str, REG_NUMBER); + } + + /** 正则验证 */ + public static boolean match(String text, String reg){ + if(text == null) { + return false; + } + return text.matches(reg); + } + + + + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SeqKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SeqKit.java new file mode 100644 index 0000000..649cc2b --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SeqKit.java @@ -0,0 +1,232 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.jeequan.jeepay.core.model.PrefixConfig; + +import java.util.Date; +import java.util.concurrent.atomic.AtomicLong; + +/* +* 序列号生成 工具类 +* +* @author terrfly +* @author jmdhappy +* +* @date 2021/6/8 16:56 +*/ +public class SeqKit { + + private static final AtomicLong PAY_ORDER_SEQ = new AtomicLong(0L); + private static final AtomicLong REFUND_ORDER_SEQ = new AtomicLong(0L); + private static final AtomicLong MHO_ORDER_SEQ = new AtomicLong(0L); + private static final AtomicLong MHO_REFUND_ORDER_SEQ = new AtomicLong(0L); + private static final AtomicLong TRANSFER_ID_SEQ = new AtomicLong(0L); + private static final AtomicLong DIVISION_BATCH_ID_SEQ = new AtomicLong(0L); + + private static final AtomicLong QRCODE_CARD_ID_SEQ = new AtomicLong(0L); //码牌自增ID + + private static final AtomicLong CASH_PLUGIN_CDKEY_ID_SEQ = new AtomicLong(0L); // 收银插件激活码自增ID + + private static final AtomicLong CASHOUT_ID_SEQ = new AtomicLong(0L); + + private static final AtomicLong FLOW_NO_ID_SEQ = new AtomicLong(0L); + + private static final AtomicLong TK_ID_SEQ = new AtomicLong(0L); + + private static final String PAY_ORDER_SEQ_PREFIX = "P"; + private static final String REFUND_ORDER_SEQ_PREFIX = "R"; + private static final String MHO_ORDER_SEQ_PREFIX = "M"; + private static final String MHO_REFUND_ORDER_SEQ_PREFIX = "MR"; + private static final String TRANSFER_ID_SEQ_PREFIX = "T"; + private static final String DIVISION_BATCH_ID_SEQ_PREFIX = "D"; + + private static final String MCH_APPLYMENT_MODIFY_PREFFIX = "SYBBG"; + + private static final String CASH_PLUGIN_CDKEY_SEQ_PREFFIX = "5"; + + private static final String CASHOUT_ID_SEQ_PREFIX = "C"; + + private static final String ACCOUNT_ID_SEQ_PREFIX = "AC"; + + private static final String APPID_PREFIX="2081"; + + public static final String TOKEN_PREFIX= "Q8"; + + /** 是否使用MybatisPlus生成分布式ID **/ + private static final boolean IS_USE_MP_ID = true; + + /** 生成支付订单号 兼容银盛 全部以日期开头 **/ + public static String genPayOrderId() { + return DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT) + IdWorker.getIdStr() + RandomUtil.randomStringUpper(3); + } + + /** 生成退款订单号 **/ + public static String genRefundOrderId() { + if(IS_USE_MP_ID) { + return REFUND_ORDER_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d",REFUND_ORDER_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) REFUND_ORDER_SEQ.getAndIncrement() % 10000); + } + + + /** 模拟生成商户订单号 **/ + public static String genMhoOrderId() { + if(IS_USE_MP_ID) { + return MHO_ORDER_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", MHO_ORDER_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) MHO_ORDER_SEQ.getAndIncrement() % 10000); + } + + /** 模拟生成商户退款订单号 **/ + public static String genMhoRefundOrderId() { + if(IS_USE_MP_ID) { + return MHO_REFUND_ORDER_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", MHO_REFUND_ORDER_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) MHO_REFUND_ORDER_SEQ.getAndIncrement() % 10000); + } + + /** 模拟生成商户订单号 **/ + public static String genTransferId() { + if(IS_USE_MP_ID) { + return TRANSFER_ID_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", TRANSFER_ID_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) TRANSFER_ID_SEQ.getAndIncrement() % 10000); + } + + /** 模拟生成分账批次号 **/ + public static String genDivisionBatchId() { + if(IS_USE_MP_ID) { + return DIVISION_BATCH_ID_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", DIVISION_BATCH_ID_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) DIVISION_BATCH_ID_SEQ.getAndIncrement() % 10000); + } + + /** 模拟生成分账批次号 **/ +// public static String genMchApplymentApplyNo() { +// if(IS_USE_MP_ID) { +// return MCH_APPLYMENT_SEQ_PREFFIX + DateUtil.format(new Date(), "yyMMdd")+ RandomUtil.randomNumbers(6); +// } +// return String.format("%s%s%04d", MCH_APPLYMENT_SEQ_PREFFIX, +// DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), +// (int) DIVISION_BATCH_ID_SEQ.getAndIncrement() % 10000); +// } + + + + public static String getMchAppId() { + return APPID_PREFIX + DateUtil.format(new Date(), "yyMMdd")+ RandomUtil.randomNumbers(6); + + } + + + /** 模拟生成分账批次号, 避免mp自增太长 导致查询失败 **/ + public static Long genQrcodeCardId() { + + return Long.parseLong(String.format("%s%02d", + DateKit.currentTimeMillis() + "", + (int) QRCODE_CARD_ID_SEQ.getAndIncrement() % 100) + ); + + } + + /** 生成收银插件 全局唯一激活码 **/ + public static String genPluginCdKey() { + return String.format("%s%s%02d",CASH_PLUGIN_CDKEY_SEQ_PREFFIX, + DateKit.currentTimeMillis() + "", + (int) CASH_PLUGIN_CDKEY_ID_SEQ.getAndIncrement() % 100); + } + + /** 生成三方账户提现单号 **/ + public static String genCashoutRecordId() { + if(IS_USE_MP_ID) { + return CASHOUT_ID_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", CASHOUT_ID_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) CASHOUT_ID_SEQ.getAndIncrement() % 10000); + } + + /** 生成账户编号 **/ + public static String genAccountNo() { + if(IS_USE_MP_ID) { + return ACCOUNT_ID_SEQ_PREFIX + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", ACCOUNT_ID_SEQ_PREFIX, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) CASHOUT_ID_SEQ.getAndIncrement() % 10000); + } + + /** + * 生成流水号 + * @param prefix + * @return + */ + public static String genFlowNo(String prefix) { + if(IS_USE_MP_ID) { + return prefix + IdWorker.getIdStr(); + } + return String.format("%s%s%04d", prefix, + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN), + (int) FLOW_NO_ID_SEQ.getAndIncrement() % 10000); + } + + /** + * 生成新的渠道号 + */ + public static String genIsvNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + return bean.getIsv() + DateUtil.year(new Date()) + RandomUtil.randomNumbers(10); + } + + public static String genAgentNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + return bean.getAgent() + DateUtil.currentSeconds() + RandomUtil.randomString("0123456789ABCDEF", 1); + } + + public static String genMchNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + return bean.getMch() + DateUtil.currentSeconds() + RandomUtil.randomString("0123456789ABCDEF", 1); + } + + public static String genMchApplyNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + return bean.getMchApplyment() + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(6); + } + + public static String genMchNotifyApplyNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + String randomCharPool = RandomUtil.BASE_NUMBER + RandomUtil.BASE_CHAR.toUpperCase(); + // 商户变更的数据基数会大一些,这里采用8位随机数 + return bean.getMchNotifyNo() + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomString(randomCharPool, 8); + } + + public static String genStoreNo() { + PrefixConfig bean = SpringUtil.getBean(PrefixConfig.class); + return bean.getStore() + DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomNumbers(4); + } + + /** 生成账户编号 **/ + public static String genTk() { + return TOKEN_PREFIX + DateUtil.format(new Date(), "yyMMddHHmmss") + RandomUtil.randomNumbers(3); + } + + public static String genTransOrderId() { + String randomCharPool = RandomUtil.BASE_NUMBER + RandomUtil.BASE_CHAR.toUpperCase(); + return DateUtil.format(new Date(), "yyMMdd") + RandomUtil.randomString(randomCharPool, 8); + } +} + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SpringBeansUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SpringBeansUtil.java new file mode 100644 index 0000000..dc27a07 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/SpringBeansUtil.java @@ -0,0 +1,56 @@ +package com.jeequan.jeepay.core.utils; + +import com.jeequan.jeepay.core.exception.BizException; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * @description: Spring 框架下, 获取Beans静态函数方法。 + * @Author terrfly + * @Date 2019/12/31 13:57 + */ +@Component +public class SpringBeansUtil implements ApplicationContextAware { + + private static ApplicationContext applicationContext = null; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if(SpringBeansUtil.applicationContext == null){ + SpringBeansUtil.applicationContext = applicationContext; + } + } + + /** 获取applicationContext */ + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** 通过name获取 Bean. */ + public static Object getBean(String name){ + + if(!getApplicationContext().containsBean(name)){ + throw new BizException("未获取到对应的实现类"); + } + + return getApplicationContext().getBean(name); + + } + + /** 通过class获取Bean. */ + public static T getBean(Class clazz){ + + return getApplicationContext().getBean(clazz); + } + + /** 通过name,以及Clazz返回指定的Bean */ + public static T getBean(String name, Class clazz){ + if(!getApplicationContext().containsBean(name)){ + return null; + } + return getApplicationContext().getBean(name, clazz); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/StringKit.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/StringKit.java new file mode 100644 index 0000000..a9e1642 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/StringKit.java @@ -0,0 +1,194 @@ +package com.jeequan.jeepay.core.utils; + +import cn.hutool.core.net.url.UrlBuilder; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.constants.CS; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/* +* String 工具类 +* +* @author terrfly +* +* @date 2021/6/8 16:58 +*/ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StringKit { + + public static String getUUID(){ + return UUID.randomUUID().toString().replace("-", "") + Thread.currentThread().getId(); + } + + public static String getUUID(int endAt){ + return getUUID().substring(0, endAt); + } + + /** 拼接url参数 **/ + public static String appendUrlQuery(String url, Map map) { + if (StringUtils.isEmpty(url) || map == null || map.isEmpty()) { + return url; + } + + StringBuilder sb = new StringBuilder(url); + if (!url.contains("?")) { + sb.append("?"); + } + + final boolean[] hasQueryCondition = {url.contains("=")}; + + String query = map.entrySet().stream() + .filter(entry -> Objects.nonNull(entry.getKey()) && Objects.nonNull(entry.getValue())) + .map(entry -> { + try { + String encodedValue = URLEncoder.encode(entry.getValue().toString(), "UTF-8"); + return entry.getKey() + "=" + encodedValue; + } catch (UnsupportedEncodingException e) { + log.info("urlEncoding异常", e); + return ""; + } + }) + .filter(s -> !s.isEmpty()) + .reduce((s1, s2) -> s1 + "&" + s2) + .orElse(""); + return sb.append(query).toString(); + } + + + /** 拼接url参数: 旧版采用Hutool方式(当回调地址是 http://abc.com/#/abc 时存在位置问题) **/ + @Deprecated + public static String appendUrlQueryWithHutool(String url, Map map){ + + if(StringUtils.isEmpty(url) || map == null || map.isEmpty()){ + return url; + } + UrlBuilder result = UrlBuilder.of(url); + map.forEach((k, v) -> { + if(k != null && v != null){ + result.addQuery(k, v.toString()); + } + }); + + return result.build(); + } + + /** 是否 http 或 https连接 **/ + public static boolean isAvailableUrl(String url){ + + if(StringUtils.isEmpty(url)){ + return false; + } + + return url.startsWith("http://") ||url.startsWith("https://"); + } + + + /** + * 对字符加星号处理:除前面几位和后面几位外,其他的字符以星号代替 + * + * @param content 传入的字符串 + * @param frontNum 保留前面字符的位数 + * @param endNum 保留后面字符的位数 + * @param starNum 指定star的数量 + * @return 带星号的字符串 + */ + @Deprecated + public static String str2Star(String content, int frontNum, int endNum, int starNum) { + + // 兼容旧版的引用, 全部使用新的脱敏规则。 + return autoDesensitization(content); + } + + + /** + * 合并两个json字符串 + * key相同,则后者覆盖前者的值 + * key不同,则合并至前者 + * @param originStr + * @param mergeStr + * @return 合并后的json字符串 + */ + public static String marge(String originStr, String mergeStr, String ifCode) { + + if (StringUtils.isAnyBlank(originStr, mergeStr)) { + return null; + } + + JSONObject originJSON = JSON.parseObject(originStr); + JSONObject mergeJSON = JSON.parseObject(mergeStr); + + if (originJSON == null || mergeJSON == null) { + return null; + } + + // 支付宝, 特殊判断 + if(CS.IF_CODE.ALIPAY.equals(ifCode)){ + JSONObject litePramsByOrigin = originJSON.getJSONObject("liteParams"); + JSONObject litePramsByMerge = mergeJSON.getJSONObject("liteParams"); + if(litePramsByOrigin != null && litePramsByMerge != null){ + originJSON.putAll(mergeJSON); + litePramsByOrigin.putAll(litePramsByMerge); + originJSON.put("liteParams", litePramsByOrigin); + return originJSON.toJSONString(); + } + } + + originJSON.putAll(mergeJSON); + return originJSON.toJSONString(); + } + + + /* + * 功能描述: 数据自动脱敏 + * @param str + * @Return: java.lang.String + * @Author: terrfly + * @Date: 2021/7/20 17:07 + */ + public static String autoDesensitization(String str){ + + if(StringUtils.isEmpty(str)){ + return str; + } + + int len = str.length(); + + //小于等于三位 格式为: **A + if(len <= 3) { + // 1位 + return len == 1 ? "*" : StringUtils.repeat("*", len - 1) + str.substring(len - 1); + } + + // 公式: 脱敏数据占据2/3 的范围。 + // 假设: 采用6的倍数组进行循环(最少两组) 循环次数为:n, 原始位数为 x, 加密数据为原始数据的两倍即 2x , + // 即: 6x·n = len, 缩小范围使得x=n,即: 7X=len + int groupSize = len / 7 + (len % 7 == 0 ? 0 : 1); + + // 截取原始字符串的位置 + int startIndex = 0; + StringBuilder result = new StringBuilder(); //最终结果 + + for (int i = 0; i < groupSize; i++) { + int endIndex = Math.min(startIndex + 7, len); + int dataSize = endIndex - startIndex; + + result.append(i == 0 ? str.substring(startIndex, startIndex + dataSize) : StringUtils.repeat("*", dataSize)); + startIndex = endIndex; + } + + return result.toString(); + } + + + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/TreeDataBuilder.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/TreeDataBuilder.java new file mode 100644 index 0000000..b4c4195 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/TreeDataBuilder.java @@ -0,0 +1,168 @@ +package com.jeequan.jeepay.core.utils; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/* + * [ 通用树状结构构造器 ] + * 解决: 将数据库查询到的多行List, 转换为层级关系的树状结构。 + * 使用方式: + * 1. 先将查询的到对象List转换为JSONObject List, + * 在转换过程中JSONObject中必须包含 [id, pid](字段名称可自定义) 【!!必须是String类型!!】 ; + * 2. 使用构造函数创建对象,参数为转换好的对象, 如果自定义字段key 则将字段名称一并传入; + * 3. 使用buildTreeString() 或者 buildTreeObject() 生成所需对象; + * +* +* @author terrfly +* +* @date 2019/12/8 06:37 +*/ +public class TreeDataBuilder { + + + /** 私有构造器 + 指定参数构造器 **/ + private TreeDataBuilder(){} + public TreeDataBuilder(Collection nodes) { + super(); + this.nodes = nodes; + } + + public TreeDataBuilder(Collection nodes, String idName, String pidName, String childrenName) { + super(); + this.nodes = nodes; + this.idName = idName; + this.sortName = idName; //排序字段,按照idName + this.pidName = pidName; + this.childrenName = childrenName; + } + + /** 自定义字段 + 排序标志 **/ + public TreeDataBuilder(Collection nodes, String idName, String pidName, String childrenName, String sortName, boolean isAscSort) { + super(); + this.nodes = nodes; + this.idName = idName; + this.pidName = pidName; + this.childrenName = childrenName; + this.sortName = sortName; + this.isAscSort = isAscSort; + } + + /** 所有数据集合 **/ + private Collection nodes; + + /** 默认数据中的主键key */ + private String idName = "id"; + + /** 默认数据中的父级id的key */ + private String pidName = "pid"; + + /** 默认数据中的子类对象key */ + private String childrenName = "children"; + + /** 排序字段, 默认按照ID排序 **/ + private String sortName = idName; + + /** 默认按照升序排序 **/ + private boolean isAscSort = true; + + // 构建JSON树形结构 + public String buildTreeString() { + List nodeTree = buildTreeObject(); + JSONArray jsonArray = new JSONArray(); + nodeTree.stream().forEach(item -> jsonArray.add(item)); + return jsonArray.toString(); + } + + // 构建树形结构 + public List buildTreeObject() { + + //定义待返回的对象 + List resultNodes = new ArrayList<>(); + + //获取所有的根节点 (考虑根节点有多个的情况, 将根节点单独处理) + List rootNodes = getRootNodes(); + + listSort(rootNodes); //排序 + + //遍历根节点对象 + for (JSONObject rootNode : rootNodes) { + + buildChildNodes(rootNode); //递归查找子节点并设置 + + resultNodes.add(rootNode); //添加到对象信息 + } + return resultNodes; + } + + /** 递归查找并赋值子节点 **/ + private void buildChildNodes(JSONObject node) { + List children = getChildNodes(node); + if (!children.isEmpty()) { + for (JSONObject child : children) { + buildChildNodes(child); + } + + listSort(children); //排序 + node.put(childrenName, children); + } + } + + /** 查找当前节点的子节点 */ + private List getChildNodes(JSONObject currentNode) { + List childNodes = new ArrayList<>(); + for (JSONObject n : nodes) { + if (currentNode.getString(idName).equals(n.getString(pidName))) { + childNodes.add(n); + } + } + return childNodes; + } + + /** 判断是否为根节点 */ + private boolean isRootNode(JSONObject node) { + boolean isRootNode = true; + for (JSONObject n : nodes) { + if (node.getString(pidName) != null && node.getString(pidName).equals(n.getString(idName))) { + isRootNode = false; + break; + } + } + return isRootNode; + } + + /** 获取集合中所有的根节点 */ + private List getRootNodes() { + List rootNodes = new ArrayList<>(); + for (JSONObject n : nodes) { + if (isRootNode(n)) { + rootNodes.add(n); + } + } + return rootNodes; + } + + /** 将list进行排序 */ + private void listSort(List list){ + Collections.sort(list, (o1, o2) -> { + + int result; + if(o1.get(sortName) instanceof Integer){ + result = o1.getInteger(sortName).compareTo(o2.getInteger(sortName)); + }else{ + result = o1.get(sortName).toString().compareTo(o2.get(sortName).toString()); + } + + if(!isAscSort){ //倒序, 取反数 + return -result; + } + + return result; + }); + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuth.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuth.java new file mode 100644 index 0000000..129063c --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuth.java @@ -0,0 +1,161 @@ +package com.jeequan.jeepay.core.utils.google; + +import org.apache.commons.codec.binary.Base32; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + * google身份验证器,java服务端实现 + * + * + * @date 2022/5/16 17:23 + */ +public class GoogleAuth { + + // 生成的key长度( Generate secret key length) + public static final int SECRET_SIZE = 10; + + public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx"; + // Java实现随机数算法 + public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG"; + // 最多可偏移的时间 + int window_size = 3; // default 3 - max 17 + + /** + * set the windows size. This is an integer value representing the number of + * 30 second windows we allow The bigger the window, the more tolerant of + * clock skew we are. + * + * @param s + * window size - must be >=1 and <=17. Other values are ignored + */ + public void setWindowSize(int s) { + if (s >= 1 && s <= 17) + window_size = s; + } + + /** + * Generate a random secret key. This must be saved by the server and + * associated with the users account to verify the code displayed by Google + * Authenticator. The user must register this secret on their device. + * 生成一个随机秘钥 + * + * @return secret key + */ + public static String generateSecretKey() { + SecureRandom sr = null; + try { + sr = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM); + sr.setSeed(Base64.decodeBase64(SEED)); + byte[] buffer = sr.generateSeed(SECRET_SIZE); + Base32 codec = new Base32(); + byte[] bEncodedKey = codec.encode(buffer); + String encodedKey = new String(bEncodedKey); + return encodedKey; + } catch (NoSuchAlgorithmException e) { + // should never occur... configuration error + } + return null; + } + + /** + * Return a URL that generates and displays a QR barcode. The user scans + * this bar code with the Google Authenticator application on their + * smartphone to register the auth code. They can also manually enter the + * secret if desired + * + * @param user + * user id (e.g. fflinstone) + * @param host + * host or system that the code is for (e.g. myapp.com) + * @param secret + * the secret that was previously generated for this user + * @return the URL for the QR code to scan + */ + public static String getQRBarcodeURL(String user, String host, String secret) { + String format = "http://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s?secret=%s"; + return String.format(format, user, host, secret); + } + + /** + * 生成一个google身份验证器,识别的字符串,只需要把该方法返回值生成二维码扫描就可以了。 + * + * @param user + * 账号 + * @param secret + * 密钥 + * @return + */ + public static String getQRBarcode(String user, String secret) { + String format = "otpauth://totp/%s?secret=%s"; + return String.format(format, user, secret); + } + + /** + * Check the code entered by the user to see if it is valid 验证code是否合法 + * + * @param secret + * The users secret. + * @param code + * The code displayed on the users device + * @param + * The time in msec (System.currentTimeMillis() for example) + * @return + */ + public boolean check_code(String secret, long code, long timeMsec) { + Base32 codec = new Base32(); + byte[] decodedKey = codec.decode(secret); + // convert unix msec time into a 30 second "window" + // this is per the TOTP spec (see the RFC for details) + long t = (timeMsec / 1000L) / 30L; + // Window is used to check codes generated in the near past. + // You can use this value to tune how far you're willing to go. + for (int i = -window_size; i <= window_size; ++i) { + long hash; + try { + hash = verify_code(decodedKey, t + i); + } catch (Exception e) { + // Yes, this is bad form - but + // the exceptions thrown would be rare and a static + // configuration problem + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + // return false; + } + if (hash == code) { + return true; + } + } + // The validation code is invalid. + return false; + } + + private static int verify_code(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException { + byte[] data = new byte[8]; + long value = t; + for (int i = 8; i-- > 0; value >>>= 8) { + data[i] = (byte) value; + } + SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1"); + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(signKey); + byte[] hash = mac.doFinal(data); + int offset = hash[20 - 1] & 0xF; + // We're using a long because Java hasn't got unsigned int. + long truncatedHash = 0; + for (int i = 0; i < 4; ++i) { + truncatedHash <<= 8; + // We are dealing with signed bytes: + // we just keep the first byte. + truncatedHash |= (hash[offset + i] & 0xFF); + } + truncatedHash &= 0x7FFFFFFF; + truncatedHash %= 1000000; + return (int) truncatedHash; + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuthUtil.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuthUtil.java new file mode 100644 index 0000000..da7c2fc --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/google/GoogleAuthUtil.java @@ -0,0 +1,38 @@ +package com.jeequan.jeepay.core.utils.google; + +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.utils.DateKit; +import org.apache.commons.lang3.StringUtils; + +/** + * google身份验证器 工具类 + */ +public class GoogleAuthUtil { + + /** + * @author: xiaoyu + * @date: 2022/5/16 18:29 + * @describe: 验证谷歌验证码是否正确, 默认时间偏移量 5 + */ + public static Boolean checkByCode(String googleCode, String googleAuthSecretKey){ + + if (StringUtils.isEmpty(googleCode)) { + throw new BizException("验证码不能为空"); + } + + if(StringUtils.isBlank(googleAuthSecretKey)) { + throw new BizException("验证密码为空"); + } + + // 谷歌验证 + long t = DateKit.currentTimeMillis(); + GoogleAuth ga = new GoogleAuth(); + ga.setWindowSize(5); // 最多可偏移的时间 + boolean checkResult = ga.check_code(googleAuthSecretKey, Long.parseLong(googleCode), t); + if (!checkResult) { + return false; + } + return true; + } + +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/AddressUtils.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/AddressUtils.java new file mode 100644 index 0000000..b50c5e5 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/AddressUtils.java @@ -0,0 +1,58 @@ +package com.jeequan.jeepay.core.utils.ip; + +import cn.hutool.http.*; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.model.ip.IpAddressResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * 获取地址类 + * + * @author ruoyi + */ +public class AddressUtils +{ + private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); + + // IP地址查询 + public static final String IP_URL = "https://whois.pconline.com.cn/ipJson.jsp"; + + // 未知地址 + public static final String UNKNOWN = "未知"; + + public static final String LOCATION_TEXT = "内网IP"; + + public static IpAddressResult getRealAddressByIP(String ip) + { + // 内网不查询 + if (IpUtils.internalIp(ip)) + { + return IpAddressResult.internal(ip); + } + try{ + HttpResponse response = HttpUtil.createGet(IP_URL) + .form("ip", ip) + .form("json", "true") + .contentType(ContentType.FORM_URLENCODED.getValue()) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.9999.999 Safari/537.36") + .execute(); + log.info("ip:{},解析地域接口返回参数:{}", ip,response.body()); + if(!response.isOk()){ + return IpAddressResult.fail(ip,"获取地理信息异常"); + } + return JSON.parseObject(response.body(), IpAddressResult.class); + }catch (Exception e){ + log.error("获取地理位置异常 {}", ip); + } + return IpAddressResult.fail(ip,"获取地理位置异常"); + } + + public static void main(String[] args) { + String ip = "111.175.29.61"; + IpAddressResult realAddressByIP = getRealAddressByIP(ip); + System.out.println(JSON.toJSONString(realAddressByIP)); + } +} diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/IpUtils.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/IpUtils.java new file mode 100644 index 0000000..8183da9 --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/utils/ip/IpUtils.java @@ -0,0 +1,265 @@ +package com.jeequan.jeepay.core.utils.ip; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** + * 获取IP方法 + * + * @author ruoyi + */ +public class IpUtils +{ + /** + * 获取客户端IP + * + * @param request 请求对象 + * @return IP地址 + */ + public static String getIpAddr(HttpServletRequest request) + { + if (request == null) + { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + * @return 结果 + */ + public static boolean internalIp(String ip) + { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + * @return 结果 + */ + private static boolean internalIp(byte[] addr) + { + if (addr == null || addr.length < 2) + { + return true; + } + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) + { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) + { + return true; + } + case SECTION_5: + switch (b1) + { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4(String text) + { + if (text.length() == 0) + { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try + { + long l; + int i; + switch (elements.length) + { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) + { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) + { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2; ++i) + { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) + { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4; ++i) + { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) + { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } + catch (NumberFormatException e) + { + return null; + } + return bytes; + } + + /** + * 获取IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp() + { + try + { + return InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException e) + { + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName() + { + try + { + return InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException e) + { + } + return "未知"; + } + + /** + * 从多级反向代理中获得第一个非unknown IP地址 + * + * @param ip 获得的IP地址 + * @return 第一个非unknown IP地址 + */ + public static String getMultistageReverseProxyIp(String ip) + { + // 多级反向代理检测 + if (ip != null && ip.indexOf(",") > 0) + { + final String[] ips = ip.trim().split(","); + for (String subIp : ips) + { + if (false == isUnknown(subIp)) + { + ip = subIp; + break; + } + } + } + return ip; + } + + /** + * 检测给定字符串是否为未知,多用于检测HTTP请求相关 + * + * @param checkString 被检测的字符串 + * @return 是否未知 + */ + public static boolean isUnknown(String checkString) + { + return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); + } +} \ No newline at end of file diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Add.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Add.java new file mode 100644 index 0000000..b00e25e --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Add.java @@ -0,0 +1,11 @@ +package com.jeequan.jeepay.core.validate; + +/** + * 校验分组 + * + * @author deng + * @since 2024/4/25 + */ +public interface Add {} + + diff --git a/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Update.java b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Update.java new file mode 100644 index 0000000..a6dcf6f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/java/com/jeequan/jeepay/core/validate/Update.java @@ -0,0 +1,4 @@ +package com.jeequan.jeepay.core.validate; + +public interface Update { +} diff --git a/jeepay-components/jeepay-components-core/src/main/resources/spy.properties b/jeepay-components/jeepay-components-core/src/main/resources/spy.properties new file mode 100644 index 0000000..9d4804f --- /dev/null +++ b/jeepay-components/jeepay-components-core/src/main/resources/spy.properties @@ -0,0 +1,9 @@ +module.log=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +logMessageFormat=com.jeequan.jeepay.core.config.SpySqlFormatConfigure +append=false +excludeCategories=info,debug,result,resultset +deregisterDrivers=true +dateFormat=yyyy-MM-dd HH:mm:ss +driverList=com.mysql.jdbc.Driver +outageDetection=true +outageDetectionInterval=2 diff --git a/jeepay-components/jeepay-components-core/src/test/java/com/.gitkeep b/jeepay-components/jeepay-components-core/src/test/java/com/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-core/src/test/resources/.gitkeep b/jeepay-components/jeepay-components-core/src/test/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jeepay-components/jeepay-components-db/pom.xml b/jeepay-components/jeepay-components-db/pom.xml new file mode 100644 index 0000000..2ec9f66 --- /dev/null +++ b/jeepay-components/jeepay-components-db/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + com.jeequan + jeepay-components-db + jar + ${isys.version} + Jeepay计全支付系统 [jeepay-service] + https://www.jeequan.com + + + com.jeequan + jeepay-components + Final + + + + + ${basedir}/../../ + + + + + + + com.jeequan + jeepay-components-core + + + + + mysql + mysql-connector-java + + + + org.mapstruct + mapstruct + + + + + com.alibaba + druid-spring-boot-starter + 1.2.6 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.baomidou + mybatis-plus-boot-starter + + + + + org.springframework.security + spring-security-core + provided + + + + com.alibaba + easyexcel + 2.1.6 + + + + + + + + src/main/resources + + + src/main/java + + **/*.xml + + + + + + diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/BaseConverter.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/BaseConverter.java new file mode 100644 index 0000000..02e3b65 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/BaseConverter.java @@ -0,0 +1,35 @@ +package com.jeequan.jeepay.converter; + +import com.jeequan.jeepay.core.entity.IsvInfo; +import com.jeequan.jeepay.core.entity.SysUser; +import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.db.entity.IsvInfoEntity; +import com.jeequan.jeepay.db.entity.SysUserEntity; +import org.mapstruct.*; + +import java.util.Map; + +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface BaseConverter { + + @BeanMapping(builder = @Builder(disableBuilder = true)) + SysUser toModel(SysUserEntity sysUserEntity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + SysUserEntity toDbEntity(SysUser model); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + IsvInfo toModel(IsvInfoEntity entity); + @BeanMapping(builder = @Builder(disableBuilder = true)) + IsvInfoEntity toDbEntity(IsvInfo model); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + void cp(ApplymentSignInfo src, @MappingTarget ApplymentSignInfo dist); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + PaywayFee cp(PaywayFee paywayFee); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + Map newPaywayFeeMap(Map paywayFee); +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/MchInfoConverter.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/MchInfoConverter.java new file mode 100644 index 0000000..3d2629b --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/MchInfoConverter.java @@ -0,0 +1,155 @@ +package com.jeequan.jeepay.converter; + +import cn.hutool.core.util.DesensitizedUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.jeequan.jeepay.core.entity.MchApplyment; +import com.jeequan.jeepay.core.entity.MchStore; +import com.jeequan.jeepay.core.entity.*; +import com.jeequan.jeepay.core.model.applyment.MchModifyApplymentModel; +import com.jeequan.jeepay.core.model.applyment.PaywayFee; +import com.jeequan.jeepay.db.entity.*; +import com.jeequan.jeepay.model.RateConfigSimple; +import org.mapstruct.*; + +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface MchInfoConverter { + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchAppEntity toDbEntity(MchApp mchApp); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + com.jeequan.jeepay.db.entity.MchStore toDbEntity(MchStore mchStore); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchApp toModel(MchAppEntity entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchApplyment toModel(com.jeequan.jeepay.db.entity.MchApplyment entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + com.jeequan.jeepay.db.entity.MchApplyment toDbEntity(MchApplyment entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchModifyApplyment toModel(MchModifyApplymentEntity entity); + + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchStore toModel(com.jeequan.jeepay.db.entity.MchStore entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "unionSearchId", ignore = true) + @Mapping(target = "modifyModel", ignore = true) + @Mapping(target = "merchantType", ignore = true) + @Mapping(target = "mchFullName", ignore = true) + @Mapping(target = "lastDate", ignore = true) + @Mapping(target = "firstDate", ignore = true) + @Mapping(target = "epUserId", ignore = true) + @Mapping(target = "agentNo", ignore = true) + MchModifyApplymentEntity toDbEntity(MchModifyApplyment entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + void cp(SettleInfo entity, @MappingTarget SettleInfo target); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + void cp(com.jeequan.jeepay.core.entity.MchApplyment srcData, @MappingTarget com.jeequan.jeepay.db.entity.MchApplyment target); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + void cp(com.jeequan.jeepay.db.entity.MchApplyment srcData, @MappingTarget com.jeequan.jeepay.core.entity.MchApplyment target); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchSubInfoEntity toDbEntity(MchSubInfo entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchSubInfo toModel(MchSubInfoEntity entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + MchSubInfo clone(MchSubInfo entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "altId", ignore = true) + @Mapping(target = "id", ignore = true) + PayInterfaceConfig toConfig(MchPayInterfaceConfig alternative); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "sort", ignore = true) + @Mapping(target = "alias", ignore = true) + @Mapping(target = "inUseFlag", ignore = true) + @Mapping(target = "id", ignore = true) + MchPayInterfaceConfig toMchConfig(PayInterfaceConfig config); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + void cp(RedPacketRule entity, @MappingTarget RedPacketRule target); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "areaCode", ignore = true) + @Mapping(target = "alipayShopCreateId", ignore = true) + @Mapping(target = "createdAt", ignore = true) + @Mapping(target = "updatedAt", ignore = true) + @Mapping(target = "remark", ignore = true) + void cp(com.jeequan.jeepay.db.entity.MchApplyment entity, @MappingTarget MchStore target); + + @Mapping(target = "alipayShopStatus", ignore = true) + @Mapping(target = "alipayShopId", ignore = true) + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "areaCode", ignore = true) + @Mapping(target = "alipayShopCreateId", ignore = true) + @Mapping(target = "createdAt", ignore = true) + @Mapping(target = "updatedAt", ignore = true) + @Mapping(target = "remark", ignore = true) + void cp(MchApplyment entity, @MappingTarget MchStore target); + + @Mapping(target = "ext", ignore = true) + @Mapping(target = "dateRange", ignore = true) + @Mapping(target = "updatedAt", ignore = true) + @Mapping(target = "range", ignore = true) + @Mapping(target = "paywayFeeDetail", ignore = true) + @Mapping(target = "mccCode", ignore = true) + @Mapping(target = "isvNo", ignore = true) + @Mapping(target = "infoType", ignore = true) + @Mapping(target = "infoId", ignore = true) + @Mapping(target = "ifCode", ignore = true) + @Mapping(target = "createdAt", ignore = true) + @BeanMapping(builder = @Builder(disableBuilder = true)) + RateConfig toRateConfig(PaywayFee paywayFee); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + @Mapping(target = "infoId", ignore = true) + void cp(RateConfigSimple rateConfigSimple, @MappingTarget RateConfig rateConfig); + + default void desensitized(MchModifyApplyment applyment) { + if (applyment == null) { + return; + } + + /* 解析进件JSON信息 对关键信息进行脱敏 */ + JSONObject applymentJson = JSON.parseObject(applyment.getApplyDetailInfo()); + + /* 公共进件参数 */ + MchModifyApplymentModel model = applymentJson.toJavaObject(MchModifyApplymentModel.class); + + applymentJson.put("settAccountNo", DesensitizedUtil.bankCard(model.getSettAccountNo())); + applymentJson.put("settAccountName", DesensitizedUtil.chineseName(model.getSettAccountName())); + applymentJson.put("settAccountIdcardNo", DesensitizedUtil.idCardNum(model.getSettAccountIdcardNo(),3, 4)); + + applyment.setApplyDetailInfo(applymentJson.toJSONString()); + } + + default void desensitized(MchModifyApplymentEntity applyment) { + if (applyment == null) { + return; + } + + /* 解析进件JSON信息 对关键信息进行脱敏 */ + JSONObject applymentJson = JSON.parseObject(applyment.getApplyDetailInfo()); + + /* 公共进件参数 */ + MchModifyApplymentModel model = applymentJson.toJavaObject(MchModifyApplymentModel.class); + + applymentJson.put("settAccountNo", DesensitizedUtil.bankCard(model.getSettAccountNo())); + applymentJson.put("settAccountName", DesensitizedUtil.chineseName(model.getSettAccountName())); + applymentJson.put("settAccountIdcardNo", DesensitizedUtil.idCardNum(model.getSettAccountIdcardNo(),3, 4)); + + applyment.setApplyDetailInfo(applymentJson.toJSONString()); + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/TransferConverter.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/TransferConverter.java new file mode 100644 index 0000000..c7e8a49 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/converter/TransferConverter.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.converter; + +import com.jeequan.jeepay.core.entity.TransferOrder; +import com.jeequan.jeepay.core.entity.TransferWallet; +import com.jeequan.jeepay.db.entity.TransferOrderEntity; +import com.jeequan.jeepay.db.entity.TransferWalletEntity; +import org.mapstruct.*; + +/** + * 代付相关实体类转换器 + * + * @author deng + * @since 2024/5/9 + */ +@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface TransferConverter { + + @BeanMapping(builder = @Builder(disableBuilder = true)) + TransferOrder toModel(TransferOrderEntity entity); + + @Mapping(target = "ext", ignore = true) + @Mapping(target = "dateRange", ignore = true) + @BeanMapping(builder = @Builder(disableBuilder = true)) + TransferOrderEntity toDbEntity(TransferOrder model); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + TransferWallet toModel(TransferWalletEntity entity); + + @BeanMapping(builder = @Builder(disableBuilder = true)) + TransferWalletEntity toDbEntity(TransferWallet entity); +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DBProp.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DBProp.java new file mode 100644 index 0000000..ac129a1 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DBProp.java @@ -0,0 +1,102 @@ +package com.jeequan.jeepay.db.config.dynamic; + +import cn.hutool.crypto.symmetric.AES; +import com.jeequan.jeepay.core.constants.CS; +import com.jeequan.jeepay.core.exception.BizException; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/*** + * DB配置信息对象 + * 全部属性来自 DruidDataSource (Extends因初始化导致启动失败) + * @author terrfly + * @date 2022/3/8 10:37 + */ +@Data +@Slf4j +public class DBProp { + + /** + * 加密对象 + **/ + private static final AES aes = new AES(CS.DB_PASSWD_DECRYPT_KEY.getBytes()); + + /** + * 是否加密账号 + **/ + private Boolean encryptAccount; + + private String url; + private String username; + private String password; + private String driverClassName; + private String dbType; + private Integer initialSize; + private Integer minIdle; + private Integer maxActive; + private Integer maxWait; + private Boolean testWhileIdle; + private Boolean testOnBorrow; + private Boolean testOnReturn; + private Integer timeBetweenEvictionRunsMillis; + private Integer minEvictableIdleTimeMillis; + private String validationQuery; + private Boolean poolPreparedStatements; + private Integer maxPoolPreparedStatementPerConnectionSize; + private String filters; + private String connectionProperties; + + + public String getUsername() { + + // 需要解密 + if (encryptAccount != null && encryptAccount) { + + try { + return aes.decryptStr(username); + } catch (Exception e) { + log.error("数据库[账号]解密失败,请检查加密数据或加密因子是否正确!", e); + throw new BizException("数据库[账号]解密失败,请检查加密数据或加密因子是否正确!"); + } + } + + return username; + } + + public String getPassword() { + + // 需要解密 + if (encryptAccount != null && encryptAccount) { + + try { + return aes.decryptStr(password); + } catch (Exception e) { + log.error("数据库[密码]解密失败,请检查加密数据或加密因子是否正确!", e); + throw new BizException("数据库[密码]解密失败,请检查加密数据或加密因子是否正确!"); + } + } + + return password; + } + + + public static void main(String[] args) { + + String text = "root"; + try { + System.out.println("加密结果: " + text + " ==> " + aes.encryptHex(text)); + } catch (Exception e) { + System.out.println("加密结果: " + text + " ==> 失败"); + } + + String entryText = "1fc401e3949581c60fef3f62d539b434"; + try { + System.out.println("解密结果: " + entryText + " ==> " + aes.decryptStr(entryText)); + } catch (Exception e) { + System.out.println("解密结果: " + entryText + " ==> 失败"); + } + + } + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceAspectj.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceAspectj.java new file mode 100644 index 0000000..0881053 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceAspectj.java @@ -0,0 +1,54 @@ +package com.jeequan.jeepay.db.config.dynamic; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 数据源切面 + * + * @author terrfly + * @date 2022/3/8 11:35 + */ +@Component +@Aspect +@Order(0) +public class DataSourceAspectj { + + /** + * 切入点 + */ + @Pointcut("@annotation(com.jeequan.jeepay.db.config.dynamic.DataSourceSwitch)") + public void dsPointCut() { + } + + /** + * 围绕事件 + */ + @Around("dsPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + + //获取方法注解 + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + + DataSourceSwitch dataSource = method.getAnnotation(DataSourceSwitch.class); + if (dataSource != null) { + DynamicDataSource.setDataSource(dataSource.value()); + } + + try { + return point.proceed(); //处理函数 + } finally { + // 销毁数据源 在执行方法之后 + DynamicDataSource.clear(); + } + } + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSpringConfig.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSpringConfig.java new file mode 100644 index 0000000..582e001 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSpringConfig.java @@ -0,0 +1,84 @@ +package com.jeequan.jeepay.db.config.dynamic; + +import cn.hutool.core.util.ObjUtil; +import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** +* +* DB spring bean 配置信息 +* @author terrfly +* @date 2022/3/8 9:39 +*/ +@Configuration +public class DataSourceSpringConfig { + + /** 获取 主 从的配置信息 **/ + @ConfigurationProperties(prefix = "db-config.master") + @Bean(name = "masterDBProp") + public DBProp masterDBProp() { return new DBProp(); } + + @ConfigurationProperties(prefix = "db-config.slave") + @Bean(name = "slaveDBProp") + public DBProp slaveDBProp() { return new DBProp(); } + + @Autowired + @Qualifier("masterDBProp") + private DBProp masterDBProp; + + @Autowired + @Qualifier("slaveDBProp") + private DBProp slaveDBProp; + + @Bean(name = "dataSource") + public DynamicDataSource dynamicDataSource() throws SQLException { + + DynamicDataSource result = new DynamicDataSource(); + + // 全部db连接池 + Map dbMap = new HashMap<>(); + dbMap.put(DynamicDataSource.MASTER, fillDS(masterDBProp)); + dbMap.put(DynamicDataSource.SLAVE, fillDS(slaveDBProp)); + + // 默认master + result.setDefaultTargetDataSource(dbMap.get(DynamicDataSource.MASTER)); + + result.setTargetDataSources(dbMap); + return result; + } + + /** 填充 datasoruce */ + private DruidDataSource fillDS(DBProp thisProp) throws SQLException { + DruidDataSource result = new DruidDataSource(); + + result.setDbType(ObjUtil.defaultIfNull(thisProp.getDbType(), masterDBProp.getDbType())); + result.setDriverClassName(ObjUtil.defaultIfNull(thisProp.getDriverClassName(), masterDBProp.getDriverClassName())); + result.setUrl(ObjUtil.defaultIfNull(thisProp.getUrl(), masterDBProp.getUrl())); + result.setUsername(ObjUtil.defaultIfNull(thisProp.getUsername(), masterDBProp.getUsername())); + result.setPassword(ObjUtil.defaultIfNull(thisProp.getPassword(), masterDBProp.getPassword())); + result.setInitialSize(ObjUtil.defaultIfNull(thisProp.getInitialSize(), masterDBProp.getInitialSize())); + result.setMinIdle(ObjUtil.defaultIfNull(thisProp.getMinIdle(), masterDBProp.getMinIdle())); + result.setMaxActive(ObjUtil.defaultIfNull(thisProp.getMaxActive(), masterDBProp.getMaxActive())); + result.setMaxWait(ObjUtil.defaultIfNull(thisProp.getMaxWait(), masterDBProp.getMaxWait())); + result.setTestWhileIdle(ObjUtil.defaultIfNull(thisProp.getTestWhileIdle(), masterDBProp.getTestWhileIdle())); + result.setTestOnBorrow(ObjUtil.defaultIfNull(thisProp.getTestOnBorrow(), masterDBProp.getTestOnBorrow())); + result.setTestOnReturn(ObjUtil.defaultIfNull(thisProp.getTestOnReturn(), masterDBProp.getTestOnReturn())); + result.setTimeBetweenEvictionRunsMillis(ObjUtil.defaultIfNull(thisProp.getTimeBetweenEvictionRunsMillis(), masterDBProp.getTimeBetweenEvictionRunsMillis())); + result.setMinEvictableIdleTimeMillis(ObjUtil.defaultIfNull(thisProp.getMinEvictableIdleTimeMillis(), masterDBProp.getMinEvictableIdleTimeMillis())); + result.setValidationQuery(ObjUtil.defaultIfNull(thisProp.getValidationQuery(), masterDBProp.getValidationQuery())); + result.setPoolPreparedStatements(ObjUtil.defaultIfNull(thisProp.getPoolPreparedStatements(), masterDBProp.getPoolPreparedStatements())); + result.setMaxPoolPreparedStatementPerConnectionSize(ObjUtil.defaultIfNull(thisProp.getMaxPoolPreparedStatementPerConnectionSize(), masterDBProp.getMaxPoolPreparedStatementPerConnectionSize())); + result.setFilters(ObjUtil.defaultIfNull(thisProp.getFilters(), masterDBProp.getFilters())); + result.setConnectionProperties(ObjUtil.defaultIfNull(thisProp.getConnectionProperties(), masterDBProp.getConnectionProperties())); + + return result; + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSwitch.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSwitch.java new file mode 100644 index 0000000..b2259d6 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DataSourceSwitch.java @@ -0,0 +1,18 @@ +package com.jeequan.jeepay.db.config.dynamic; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 切换数据源 注解 + * 在方法层面上添加 @DataSourceSwitch(DynamicDataSource.MASTER) 即可切换数据源 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface DataSourceSwitch { + + /** 默认使用Master */ + DynamicDataSource.DataSourceTypeEnum value() default DynamicDataSource.DataSourceTypeEnum.MASTER; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DynamicDataSource.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DynamicDataSource.java new file mode 100644 index 0000000..f8151d9 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/config/dynamic/DynamicDataSource.java @@ -0,0 +1,51 @@ +package com.jeequan.jeepay.db.config.dynamic; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** +* 动态数据源 和 管理类 +* +* @author terrfly +* @date 2022/3/8 9:29 +*/ +public class DynamicDataSource extends AbstractRoutingDataSource { + + /** 数据源枚举值 主 / 从 */ + public enum DataSourceTypeEnum { MASTER, SLAVE } + + public static final DataSourceTypeEnum MASTER = DataSourceTypeEnum.MASTER; + public static final DataSourceTypeEnum SLAVE = DataSourceTypeEnum.SLAVE; + + //当前线程 用于存放使用中的数据源 + private static final ThreadLocal CURRENT_DATA_SOURCE = new ThreadLocal<>(); + + /** + * 设置使用数据源 + * @param dataSource + */ + public static void setDataSource(DataSourceTypeEnum dataSource){ + CURRENT_DATA_SOURCE.set(dataSource); + } + + /** + * 获取当前数据源 + * @return DataSourceTypeEnum + */ + public static DataSourceTypeEnum getCurrentDataSource(){ + return CURRENT_DATA_SOURCE.get(); + } + + /** + * 清空使用数据源, 使用默认数据源 + */ + public static void clear(){ + CURRENT_DATA_SOURCE.remove(); + } + + /** 覆写 determineCurrentLookupKey 函数 **/ + @Override + protected Object determineCurrentLookupKey() { + return DynamicDataSource.getCurrentDataSource(); + } + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountChangeInfo.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountChangeInfo.java new file mode 100644 index 0000000..75aa03f --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountChangeInfo.java @@ -0,0 +1,122 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.jeequan.jeepay.core.entity.AccountOperate; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * 账户变动明细 + *

+ * + * @author [mybatis plus generator] + * @since 2023-12-11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_account_change_info") +@NoArgsConstructor +@AllArgsConstructor +public class AccountChangeInfo extends BaseModel { + + private static final long serialVersionUID=1L; + + public static final LambdaQueryWrapper gw(AccountChangeInfo accountInfo){ + return new LambdaQueryWrapper<>(accountInfo); + } + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + /** + * 流水号 + */ + @TableId(type = IdType.INPUT) + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String flowNo; + + /** + * 账户编号 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String accountNo; + + /** + * 用户号 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String mchNo; + + /** + * 账户类型 0:退款账户 1:营销账户 2:虚拟银行 3:钱包 4 手续费账户 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte accountType; + + /** + * 变动类型 0:充值 1:提现 2:转账 3:退款 4:扣除 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte changeType; + + /** + * 变动方式 0:扫码充值 1:对公转账 2:账户提现 3:平台户退款 -1:提现驳回 4:直付通 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte changeMethod; + + /** + * 变动前余额 + */ + private Long beforeAmt; + + /** + * 变动金额 + */ + private Long changeAmt; + + + + /** + * 变动后的金额 + */ + private Long afterAmt; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + private String remark; + + + public AccountChangeInfo(AccountOperate operate,AccountInfo account) { + this.flowNo = operate.getOrderId(); + this.accountNo = operate.getAccountNo(); + this.mchNo = account.getInfoId(); + this.accountType = account.getType(); + this.changeType = operate.getChangeType(); + this.beforeAmt = account.getBalacne(); + this.changeAmt = operate.getChangeAmt(); + this.afterAmt = BigDecimal.valueOf(account.getBalacne()).add(BigDecimal.valueOf(operate.getChangeAmt())).longValue(); + this.remark = operate.getRemark(); + this.changeMethod = operate.getChangeMethod(); + } + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountFundInfo.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountFundInfo.java new file mode 100644 index 0000000..dbc460d --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountFundInfo.java @@ -0,0 +1,353 @@ +package com.jeequan.jeepay.db.entity; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.jeequan.jeepay.core.entity.AccountOperate; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.*; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * + *

+ * 账户资金明细 + * @author [mybatis plus generator] + * @since 2024-03-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_account_fund_info",autoResultMap = true) +@NoArgsConstructor +@AllArgsConstructor +public class AccountFundInfo extends BaseModel { + + /** + * 打款类型 手动 + */ + public static final byte MANUAL = 0; + + /** + * 打款类型 灵工 + */ + public static final byte FLEXIBLE = 1; + + private static final long serialVersionUID=1L; + + public static LambdaQueryWrapper gw(AccountFundInfo info) { + return new LambdaQueryWrapper<>(info); + } + + public static LambdaQueryWrapper gw() { + return new LambdaQueryWrapper<>(); + } + + /** + * 状态 0:订单生成 -1:失败 1:审核中 2:打款中 3:成功 + */ + + public static final byte INIT = 0; + + public static final byte FAIL = -1; + + public static final byte AUDIT = 1; + + public static final byte PAYMENT = 2; + + public static final byte SUCCESS = 3; + + /** + * 付款方式 WECHAT:微信 ALIPAY:支付宝 BANK 银行卡 + */ + public static final String WECHAT = "WECHAT"; + + public static final String ALIPAY = "ALIPAY"; + + public static final String BANK = "BANK"; + + /** + * 订单号 + */ + @TableId(type = IdType.INPUT) + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String orderId; + + /** + * 账户编号 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String accountNo; + + /** + * 渠道流水号 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String channelOrderId; + + /** + * 用户号 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String mchNo; + + /** + * 账户类型 0:退款账户 1:营销账户 2:虚拟银行 3:钱包 取值 ACCOUNT_INFO 的枚举类 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte accountType; + + /** + * 变动类型 0:充值 1:提现 2:转账 3:退款 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte changeType; + + /** + * 变动方式 0:扫码充值 1:对公转账 2:账户提现 3:平台户退款 -1:提现驳回 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte changeMethod; + + /** + * 金额 + */ + private Long amount; + + /** + * 实际金额 + */ + private Long finalAmount; + + /** + * 手续费 + */ + private Long fee; + + /** + * 状态 0:订单生成 -1:失败 1:审核中 2:打款中 3:成功 + */ + @TableField(whereStrategy = FieldStrategy.NOT_NULL) + private Byte state; + + /** + * 渠道 + */ + @TableField(whereStrategy = FieldStrategy.NOT_EMPTY) + private String ifCode; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + /** + * 扩展参数 + */ + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject extra; + + /** + * 渠道返回参数 + */ + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject channelExtra; + + /** + * 付款方式 WECHAT:微信 ALIPAY:支付宝 BANK 银行卡 + */ + private String payMethod; + + /** + * 收款商户号 + */ + private String mchExtNo; + + /** + * 变动金额 + */ + @TableField(exist = false) + private Long changeAmt; + + /** + * 0:手动打款 1:灵工打款 + */ + @TableField(exist = false) + private Byte mark; + + @TableField(exist = false) + private String accountTypeDesc; + + @TableField(exist = false) + private String changeTypeDesc; + + @TableField(exist = false) + private String changeMethodDesc; + + @TableField(exist = false) + private String stateDesc; + + @Getter + @AllArgsConstructor + public enum ChangeType{ + + RECHARGE((byte)0,"充值"), + + CASH((byte)1,"提现"), + + TRANSFER((byte)2,"转账"), + + REFUND((byte)3,"退款"), + + DEDUCT((byte)4,"抵扣") + ; + + private final Byte value; + + private final String desc; + + public static ChangeType getVal(byte value){ + ChangeType[] values = values(); + for (ChangeType val:values) { + if(val.getValue() == value){ + return val; + } + } + throw new BizException("充值类型非法"); + } + } + + @Getter + @AllArgsConstructor + public enum ChangeMethod{ + + REJECT((byte)-1,"驳回"), + + SCAN((byte)0,"扫码充值"), + + PUBIC((byte)1,"对公转账"), + + ACCOUNT_CASH((byte)2,"账户提现"), + + YBH_REFUND((byte)3,"一般户退款"), + + ZFT((byte)4,"直付通"), + + DF((byte)5,"代发"); + + private final Byte value; + + private final String desc; + + public static ChangeMethod getVal(byte value){ + ChangeMethod[] values = values(); + for (ChangeMethod val:values) { + if(val.getValue() == value){ + return val; + } + } + throw new BizException("变动类型非法"); + } + } + + /** + * 构建账户资金明细 + * @param operate + */ + public AccountFundInfo(AccountOperate operate,AccountInfo account,String payMethod) { + this.orderId = operate.getOrderId(); + this.accountNo = operate.getAccountNo(); + this.mchNo = account.getInfoId(); + this.accountType = account.getType(); + this.changeType = operate.getChangeType(); + this.changeMethod = operate.getChangeMethod(); + this.amount = operate.getAmount(); + this.finalAmount = operate.getFinalAmt(); + this.fee = BigDecimal.valueOf(operate.getAmount()).subtract(BigDecimal.valueOf(operate.getFinalAmt())).longValue(); + if(operate.getState() != null){ + this.state = operate.getState(); + }else{ + this.state = INIT; + } + this.ifCode = operate.getIfCode(); + this.remark = operate.getRemark(); + this.mchExtNo = operate.getMchExtNo(); + this.payMethod = payMethod; + this.changeAmt = operate.getChangeAmt(); + this.extra = operate.getExtra(); + } + + public AccountFundInfo(AccountOperate operate,AccountInfo account) { + this(operate,account,BANK); + } + + + public String getAccountTypeDesc() { + if(this.getAccountType() == null){ + return ""; + } + return AccountInfo.Type.getVal(this.getAccountType()).getDesc(); + } + + public String getChangeTypeDesc() { + if(this.getChangeType() == null){ + return ""; + } + return ChangeType.getVal(this.getChangeType()).getDesc(); + } + + public String getChangeMethodDesc() { + if(this.getChangeMethod() == null){ + return ""; + } + return ChangeMethod.getVal(this.getChangeMethod()).getDesc(); + } + + /** + * 0:待处理 -1:失败 1:审核中 2:打款中 3:成功 + * @return + */ + public String getStateDesc() { + if(this.getState() == null){ + return ""; + } + if(this.getState() == FAIL){ + return "失败"; + } + if(this.getState() == 0){ + return "初始化"; + } + if(this.getState() == AUDIT){ + return "审核中"; + } + + if(this.getState() == PAYMENT){ + return "打款中"; + } + + if(this.getState() == SUCCESS){ + return "成功"; + } + + return "未知"; + } +} + + + diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountInfo.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountInfo.java new file mode 100644 index 0000000..b9ab6c0 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AccountInfo.java @@ -0,0 +1,278 @@ +package com.jeequan.jeepay.db.entity; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +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.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.jeequan.jeepay.core.entity.AccountCashInfo; +import com.jeequan.jeepay.core.entity.AccountRuleExt; +import com.jeequan.jeepay.core.exception.BizException; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; +import java.util.List; + +/** + *

+ * 账户表 + *

+ * + * @author [mybatis plus generator] + * @since 2023-12-11 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_account_info",autoResultMap = true) +public class AccountInfo extends BaseModel { + + public static final LambdaQueryWrapper gw(AccountInfo accountInfo){ + return new LambdaQueryWrapper<>(accountInfo); + } + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** + * 开启 + */ + public static final Byte REMIND_OPNE = 1; + + /** + * 关闭 + */ + public static final Byte REMIND_CLOSE = 0; + + /** + * 账户编号 + */ + @TableId + private String accountNo; + + /** + * 账户所属id + */ + private String infoId; + + /** + * 账户所属类型 + */ + private String infoType; + + /** + * 账户类型 0:退款账户 1:营销账户 2:虚拟银行 3:钱包 4:手续费账户 + */ + private Byte type; + + /** + * 余额 + */ + private Long balacne; + + /** + * 不可用余额 + */ + private Long freeze; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + + @Getter + @AllArgsConstructor + public enum Type{ + + REFUND((byte)0,"退款账户"), + + MARKET((byte)1,"营销账户"), + + VIRTUALLY((byte)2,"虚拟银行账户"), + + WALLET((byte)3,"钱包账户"), + + SERVICE_CHARGE((byte)4,"手续费账户"); + + private final Byte type; + + private final String desc; + + public static Type getVal(byte value){ + Type[] values = values(); + for (Type val:values) { + if(val.getType() == value){ + return val; + } + } + throw new BizException("账户类型非法"); + } + } + + @TableField(exist = false) + private String typeNameDesc; + + public String getTypeNameDesc() { + if(type == null){ + return ""; + } + Type val = Type.getVal(this.getType()); + return val.getDesc(); + } + + + @TableField(exist = false) + private String realName; + + @TableField(exist = false) + private String phone; + + /** + * 充值金额 + */ + @TableField(exist = false) + private Long rechargeAmt; + + /** + * 是否开通提醒 + */ + private Byte remindState; + + /** + * 提醒规则 + */ + @TableField(value = "remind_rule_ext",typeHandler = FastjsonTypeHandler.class) + private JSONObject remindRuleExt; + /** + * 最后通知时间 + */ + private Date lastNoticeTime; + + @TableField(exist = false) + private AccountRuleExt ruleExt; + + /** + * 提现信息 + */ + @TableField(exist = false) + private AccountCashInfo cashInfo; + + public void preRuleCheck() { + if(this.getAccountNo() == null){ + throw new BizException("账户编号不能为空"); + } + if(this.getRemindState() == null){ + throw new BizException("提醒状态不能为空"); + } + if(REMIND_OPNE.equals(this.getRemindState())){ + if(this.getRuleExt() == null){ + throw new BizException("开启预警提醒时,请设置预警规则"); + } + Long amount = this.getRuleExt().getAmount(); + if(amount == null){ + throw new BizException("预警规则临界金额不能为空"); + } + List typeList = this.getRuleExt().getTypeList(); + if(typeList == null || typeList.isEmpty()){ + throw new BizException("预警规则提醒方式至少需要勾选一项"); + } + Integer interval = this.getRuleExt().getInterval(); + if(interval == null){ + throw new BizException("预警规则提醒频率不能为空"); + } + List receiveList = this.getRuleExt().getReceiveList(); + if(receiveList == null || receiveList.isEmpty()){ + throw new BizException("预警规则接收信息人不能为空"); + } + if(receiveList.size() > 5){ + throw new BizException("接收人设置超出上限"); + } + boolean email = typeList.contains(AccountRuleExt.EMAIL); + boolean phone = typeList.contains(AccountRuleExt.PHONE); + boolean emailCheck = true; + boolean phoneCheck = true; + for (JSONObject receive:receiveList) { + if(email){ + String receEmail = receive.getString(AccountRuleExt.EMAIL); + if(StringUtils.isEmpty(receEmail)){ + emailCheck = false; + } + } + if(phone){ + String recePhone = receive.getString(AccountRuleExt.PHONE); + if(StringUtils.isEmpty(recePhone)){ + phoneCheck = false; + } + } + } + if(email && !emailCheck){ + throw new BizException("预警规则提醒方式包含了[邮箱方式],接收人信息中请填写邮箱"); + } + if(phone && !phoneCheck){ + throw new BizException("预警规则提醒方式包含了[短信方式],接收人信息中请填写手机号"); + } + this.remindRuleExt = (JSONObject) JSON.toJSON(this.getRuleExt()); + }else{ + this.remindRuleExt = null; + } + } + + public void preCashCheck() { + if(this.getAccountNo() == null){ + throw new BizException("账户编号不能为空"); + } + AccountCashInfo cashInfo = this.getCashInfo(); + if(cashInfo == null){ + throw new BizException("提现信息为空"); + } + Long cashAmt = cashInfo.getCashAmt(); + if(cashAmt == null || cashAmt <= 0){ + throw new BizException("提现金额不能为空或提现金额必须要大于0"); + } + String settleName = cashInfo.getSettleName(); + if(StringUtils.isEmpty(settleName)){ + throw new BizException("结算人名称不能为空"); + } + String settleNo = cashInfo.getSettleNo(); + if(StringUtils.isEmpty(settleNo)){ + throw new BizException("结算人银行卡号不能为空"); + } + String bankCardAreaCode = cashInfo.getBankCardAreaCode(); + if(StringUtils.isEmpty(bankCardAreaCode)){ + throw new BizException("结算人银行卡开户省市区编码不能为空"); + } + String bankCardAreaName = cashInfo.getBankCardAreaName(); + if(StringUtils.isEmpty(bankCardAreaName)){ + throw new BizException("结算人银行卡开户省市区不能为空"); + } + String bankName = cashInfo.getBankName(); + if(StringUtils.isEmpty(bankName)){ + throw new BizException("结算人银行卡开户行不能为空"); + } + String settleCard = cashInfo.getSettleCard(); + if(StringUtils.isEmpty(settleCard)){ + throw new BizException("结算人身份证号不能为空"); + } + String bankMobile = cashInfo.getBankMobile(); + if(StringUtils.isEmpty(bankMobile)){ + throw new BizException("开户行手机号不能为空"); + } + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentConfig.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentConfig.java new file mode 100644 index 0000000..600160f --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentConfig.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.db.entity; + +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; + +/** + *

+ * 商户配置表 + *

+ * + * @author [mybatis plus generator] + * @since 2023-03-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_agent_config") +public class AgentConfig extends BaseModel { + + private static final long serialVersionUID=1L; + + /** 当前服务商进件配置管理方式: configVal: DEF-平台全局默认配置 , CUSTOM-自定义 **/ + public static final String KEY_APPLYMENT_AUDIT_MODE = "applymentAuditMode"; + public static final String KEY_APPLYMENT_AUDIT_MODE_DEF = "DEF"; + public static final String KEY_APPLYMENT_AUDIT_MODE_CUSTOM = "CUSTOM"; + + /** 当前服务商进件是否需要运营平台预审核 **/ + public static final String KEY_AGENT_APPLYMENT_PRE_AUDIT_CONFIG = "agentApplymentPreAuditConfig"; + + /** 服务商发起进件时间限制: configVal: + * [开始时间, 结束时间], // 若为空表示不限制。 + * **/ + public static final String KEY_AGENT_APPLY_TIME_LIMIT_CONFIG = "agentApplyTimeLimitConfig"; + + /** 同步对象的类型 allCurrentAndSubAgent-当前及所有下级**/ + public static final String IF_ALL_CURRENT_AND_SUB_AGENT = "allCurrentAndSubAgent"; + + /** 服务商进件配置group_key **/ + public static final String GROUP_KEY_APPLYMENT_CONFIG = "applymentConfig"; + + /** + * 服务商子商户配置微信参数权限 + **/ + public static final String CONFIG_KEY_WX_CONFIG_IS_USABLE_CONFIG = "subMchWxConfigIsUsable"; + /** + * 服务商子商户配置支付接口权限 + **/ + public static final String CONFIG_KEY_MCH_PAY_INTERFACE_IS_USABLE_CONFIG = "subMchPayInterfaceConfigIsUsable"; + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + public AgentConfig(){} + + public AgentConfig(String agentNo, String configKey, String configVal, String groupKey){ + this.agentNo = agentNo; + this.configKey = configKey; + this.configVal = configVal; + this.groupKey = groupKey; + } + + /** + * 服务商号 + */ + private String agentNo; + + /** + * 配置KEY + */ + private String configKey; + + /** + * 配置内容项 + */ + private String configVal; + + /** + * 配置分组 + */ + private String groupKey; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentInfo.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentInfo.java new file mode 100644 index 0000000..d43efc6 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/AgentInfo.java @@ -0,0 +1,256 @@ +package com.jeequan.jeepay.db.entity; + +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.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +import java.util.Date; + +/** + *

+ * 服务商信息表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-03-12 + */ + +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName("t_agent_info") +public class AgentInfo extends BaseModel { + + public static LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** 待审核 **/ + public static final byte AUDIT_STATE_ING = 2; + /** 审核驳回 **/ + public static final byte AUDIT_STATE_FALSE = 3; + /** 未认证 **/ + public static final byte AUDIT_STATE_UN_AUTH = 4; + + /** + * 服务商账号 + */ + @TableId + private String agentNo; + + /** + * 服务商名称 + */ + private String agentName; + + /** + * 服务商简称 + */ + private String agentShortName; + + /** + * 服务商号 + */ + private String isvNo; + + /** + * 上级服务商号, 空串表示顶级服务商 + */ + private String pid; + + private String pidArr; + + /** + * 上级服务商简称 + */ + private String pname; + + /** + * 联系人姓名 + */ + private String contactName; + + /** + * 联系人手机号 + */ + private String contactTel; + + /** + * 联系人邮箱 + */ + private String contactEmail; + + /** + * 服务商状态: 0-停用, 1-正常, 2-待审核, 3-审核驳回, 4-未认证 + */ + private Byte state; + + /** + * 服务商等级 + */ + private Integer level; + + /** + * 是否允许发展子代理: 0-不允许, 1-允许 + */ + private Byte addAgentFlag; + + /** + * 是否允许发展子商户: 0-不允许, 1-允许 + */ + private Byte addMchFlag; + + /** + * 服务商备注 + */ + private String remark; + + /** + * 审核备注 + */ + private String auditRemark; + + /** + * 手续费计算公式类型: 1-使用系统默认配置, 2-自定义 + */ + private Byte cashoutFeeRuleType; + + /** + * 手续费计算公式 + */ + private String cashoutFeeRule; + + /** + * 结算账户类型: WX_CASH-微信零钱; ALIPAY_CASH-支付宝转账; BANK_CARD-银行卡; BANK_PUBLIC-对公; BANK_PRIVATE-对私 + */ + private String settAccountType; + + /** + * 结算账户账号 + */ + private String settAccountNo; + + /** + * 结算账户姓名 + */ + private String settAccountName; + + /** + * 结算账户开户行名称 + */ + private String settAccountBank; + + /** + * 开户行支行名称 + */ + private String settAccountSubBank; + + /** + * 结算账户联系人手机号(一般为服务商手机号) + */ + private String settAccountTelphone; + + /** + * 营业执照图片 + */ + private String licenseImg; + + /** + * 身份证人像面照片 + */ + private String idcard1Img; + + /** + * 身份证国徽面照片 + */ + private String idcard2Img; + + /** + * 手持身份证图片 + */ + private String idcardInHandImg; + + /** + * 银行卡图片 + */ + private String bankCardImg; + + /** + * 许可证照片 + */ + private String permitImg; + + /** + * 服务商类型: 1-个人, 2-企业 + */ + private Byte agentType; + + /** + * 是否为贴牌,1-是;0-否 + */ + private Byte oemType; + + /** + * 初始用户ID(创建服务商时,允许服务商登录的用户) + */ + private Long initUserId; + + /** + * 登录用户名 + */ + private String loginUsername; + + /** + * 支付密码(敏感信息密码Sensitive information password) + */ + private String sipw; + + /** + * 钱包冻结金额, 单位分 + */ + private Long freezeAmount; + + /** + * 冻结原因 + */ + private String freezeDesc; + + /** + * 创建者用户ID + */ + private Long createdUid; + + /** + * 创建者姓名 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + /** + * 邀请码 + */ + @TableField(exist = false) + private String inviteCode; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranch.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranch.java new file mode 100644 index 0000000..8b54edb --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranch.java @@ -0,0 +1,49 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 支行信息表 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_bank_branch") +public class BankBranch extends BaseModel { + + private Integer id; + + /** + * 支行联行号 + */ + private String branchNo; + + /** + * 支行名称 + */ + private String branchName; + + /** + * 银行code + */ + private String bankCode; + + /** + * 斗拱银行编码 + */ + private String bankCodeDg; + + private String bankName; + + private String provinceCode; + + private String provinceName; + + private String cityCode; + + private String cityName; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchAlipay.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchAlipay.java new file mode 100644 index 0000000..5b5fc31 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchAlipay.java @@ -0,0 +1,66 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * 支付宝支行信息 + *

+ * + * @author [mybatis plus generator] + * @since 2024-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_bank_branch_alipay") +public class BankBranchAlipay implements Serializable { + + private static final long serialVersionUID=1L; + + /** + * 联行号 + */ + @TableId(type = IdType.INPUT) + private String branchNo; + + /** + * 支行名称 + */ + private String branchName; + + /** + * 银行名称 + */ + private String bankName; + + /** + * 省 + */ + private String provinceName; + + /** + * 市 + */ + private String cityName; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchLkl.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchLkl.java new file mode 100644 index 0000000..28fabac --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchLkl.java @@ -0,0 +1,36 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_bank_branch_lkl") +public class BankBranchLkl extends BaseModel { + + @TableId("contact_line") + private String contactLine; + + + @TableField("branch_name") + private String branchName; + + + @TableField("bank_type") + private String bankType; + + + @TableField("bank_name") + private String bankName; + + + @TableField("city_code") + private String cityCode; + + @TableField("clear_no") + private String clearNo; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchZft.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchZft.java new file mode 100644 index 0000000..b5832d2 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/BankBranchZft.java @@ -0,0 +1,26 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 直付通支行数据 + * @author deng + * @since 2024/4/7 + */ +@TableName("t_bank_branch_zft") +@Data +public class BankBranchZft { + + private String branchNo; + + private String branchName; + + private String bankName; + + private String bankAbbr; + + private String province; + + private String city; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CacheTk.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CacheTk.java new file mode 100644 index 0000000..1f88de0 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CacheTk.java @@ -0,0 +1,74 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.jeequan.jeepay.core.utils.SeqKit; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * tk缓存表 + *

+ * + * @author [mybatis plus generator] + * @since 2024-02-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_cache_tk") +@NoArgsConstructor +public class CacheTk implements Serializable { + + private static final long serialVersionUID=1L; + + @TableId(type = IdType.INPUT) + private String tk; + + // 二维码扫码类型: 1 - 统一下单的聚合二维码, 2 - 码牌二维码 3 - 设备二维码 4:路由二维码 + private Byte type; + + /** + * 原id 对应设备编号 二维码编号 + */ + private String sourceId; + + /** + * 金额 + */ + private Long amount; + + /** + * 创建时间 + */ + private Date createdAt; + + + public CacheTk(Byte type, String sourceId, Long amount) { + this.tk = SeqKit.genTk(); + this.type = type; + this.sourceId = sourceId; + this.amount = amount; + } + + public CacheTk(Byte type, String sourceId) { + this(type,sourceId,null); + } + + public CacheTk(String tk, byte type, String sourceId,Long amount) { + this.tk = tk; + this.type = type; + this.sourceId = sourceId; + this.amount = amount; + } + public CacheTk(String tk, byte type, String sourceId) { + this(tk,type,sourceId,null); + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CashoutRecord.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CashoutRecord.java new file mode 100644 index 0000000..1edf459 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CashoutRecord.java @@ -0,0 +1,199 @@ +package com.jeequan.jeepay.db.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; + +/** + *

+ * 提现结算记录表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-03-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_cashout_record") +public class CashoutRecord extends com.jeequan.jeepay.core.entity.CashoutRecord { + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + 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; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/ChannelAccountCashoutRecord.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/ChannelAccountCashoutRecord.java new file mode 100644 index 0000000..921697d --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/ChannelAccountCashoutRecord.java @@ -0,0 +1,152 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + *

+ * 提现结算记录表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-11-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_channel_account_cashout_record") +public class ChannelAccountCashoutRecord extends com.jeequan.jeepay.core.entity.ChannelAccountCashoutRecord { + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + 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 + */ + @TableId + 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; + + /** + * 商户号 + */ + private String mchExtNo; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckBatch.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckBatch.java new file mode 100644 index 0000000..71b150d --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckBatch.java @@ -0,0 +1,144 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + *

+ * 对账批次表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-09-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_check_batch") +public class CheckBatch extends com.jeequan.jeepay.core.entity.CheckBatch { + + private static final long serialVersionUID=1L; + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + /** + * 对账批次号,支付接口代码ifCode_渠道商户号_对账日期 + */ + @TableId + 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; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckChannelBill.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckChannelBill.java new file mode 100644 index 0000000..cb1af91 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckChannelBill.java @@ -0,0 +1,129 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +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; + +/** + *

+ * 渠道对账单表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-09-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_check_channel_bill") +public class CheckChannelBill extends BaseModel { + + private static final long serialVersionUID=1L; + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + public static String BILL_TYPE_PAY = "pay"; // 支付账单 + public static String BILL_TYPE_REFUND = "refund"; // 退款账单 + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 对账批次号,支付接口代码ifCode_渠道商户号_对账日期 + */ + private String batchNo; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 渠道商户号 + */ + private String channelMchNo; + + /** + * 对账日期 + */ + private Date billDate; + + /** + * 账单类型,pay:支付, refund:退款 + */ + private String billType; + + /** + * 三位货币代码,人民币:cny + */ + private String currency; + + /** + * 平台订单号 + */ + private String orderId; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 交易金额 单位:分 + */ + private Long channelAmount; + + /** + * 渠道手续费 单位:分 + */ + private Long channelFeeAmount; + + /** + * 渠道交易成功时间 + */ + private Date channelSuccessAt; + + /** + * 渠道用户标识,如微信openId,支付宝账号 + */ + private String channelUser; + + /** + * 渠道订单状态:0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte channelState; + + /** + * 退款原支付订单号 + */ + private String orgPayOrderId; + + /** + * 退款金额 + */ + private String channelRefundAmount; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckDiff.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckDiff.java new file mode 100644 index 0000000..4bd7784 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/CheckDiff.java @@ -0,0 +1,195 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +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; + +/** + *

+ * 对账差异表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-09-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_check_diff") +public class CheckDiff extends BaseModel { + + private static final long serialVersionUID=1L; + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + public static String DIFF_TYPE_LOCAL = "local"; // 长款 + public static String DIFF_TYPE_CHANNEL = "channel"; // 短款 + public static String DIFF_TYPE_ORDER = "order"; // 订单差异 + + public static byte HANDLE_STATE_WAITING = 0; + public static byte HANDLE_STATE_HANG_UP = 1; + public static byte HANDLE_STATE_SUCCESS = 2; + public static byte HANDLE_STATE_IGNORE = 3; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 对账批次号,支付接口代码ifCode_渠道商户号_对账日期 + */ + private String batchNo; + + /** + * 支付接口代码 + */ + private String ifCode; + + /** + * 渠道商户号 + */ + private String channelMchNo; + + /** + * 对账日期 + */ + private Date billDate; + + /** + * 账单类型,pay:支付, refund:退款 + */ + private String billType; + + /** + * 平台订单ID + */ + private String orderId; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 商户名称 + */ + private String mchName; + + /** + * 商户应用AppId + */ + private String mchAppId; + + /** + * 商户订单号 + */ + private String mchOrderNo; + + /** + * 平台交易金额,单位分 + */ + private Long amount; + + /** + * 平台手续费,单位分 + */ + private Long feeAmount; + + /** + * 平台退款金额 + */ + private Long refundAmount; + + /** + * 平台订单状态:0-订单 生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte orderState; + + /** + * 平台交易成功时间 + */ + private Date orderSuccessAt; + + /** + * 平台下单时间 + */ + private Date orderCreateAt; + + /** + * 渠道订单号 + */ + private String channelOrderNo; + + /** + * 渠道订单状态:0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭 + */ + private Byte channelState; + + /** + * 渠道交易金额,单位分 + */ + private Long channelAmount; + + /** + * 渠道退款金额 + */ + private Long channelRefundAmount; + + /** + * 渠道手续费 + */ + private Long channelFeeAmount; + + /** + * 渠道交易成功时间 + */ + private Date channelSuccessAt; + + /** + * 差异类型:local-长款 channel-短款 order-订单差异(金额差异等) + */ + private String diffType; + + /** + * 类型:0-未处理,1-挂账,2-已处理,3-已忽略 + */ + private Byte handleState; + + /** + * 处理备注 + */ + private String handleRemark; + + /** + * 差异处理者ID + */ + private Long handleUid; + + /** + * 差异处理者姓名 + */ + private String handleBy; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DeviceProvideConfig.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DeviceProvideConfig.java new file mode 100644 index 0000000..285059a --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DeviceProvideConfig.java @@ -0,0 +1,88 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +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; + +/** + *

+ * 设备厂商配置表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_device_provide_config") +public class DeviceProvideConfig extends BaseModel { + + private static final long serialVersionUID=1L; + + //gw + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + public final static byte DEVICE_TYPE_SPEAKER = 1; + public final static byte DEVICE_TYPE_PRINTER = 2; + public final static byte DEVICE_TYPE_POS = 3; + public final static byte DEVICE_TYPE_AUTO_POS = 4; + public final static byte DEVICE_TYPE_PLUGIN = 5; + + /** + * 厂商配置ID + */ + @TableId(value = "config_id", type = IdType.AUTO) + private Long configId; + + /** + * 厂商配置备注信息, 会在商户侧进行回显 + */ + private String configDesc; + + /** + * 设备类型: 1-云喇叭, 2-云打印, 3-扫码pos, 4-智能pos, 5-收银插件 + */ + private Byte deviceType; + + /** + * 设备厂商: zgwl-智谷物联, bsj-博实结, fe-飞鹅, ps-品生, clj-财来聚, wsy-微收银, xjl-小精灵 + */ + private String provider; + + /** + * 厂商配置参数appId(扫码POS定义唯一appId) + */ + private String appId; + + /** + * 厂商配置参数,json字符串 + */ + private String providerParams; + + /** + * 状态: 0-停用,1-启用 + */ + private Byte state; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionSubject.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionSubject.java new file mode 100644 index 0000000..65d8c3b --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionSubject.java @@ -0,0 +1,145 @@ +package com.jeequan.jeepay.db.entity; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +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.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * + *

+ * + * @author [mybatis plus generator] + * @since 2024-04-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_division_subject",autoResultMap = true) +public class DivisionSubject extends BaseModel { + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** + *接收方类型 + */ + public static final byte RECEIVE_TYPE = 0; + + /** + *分出方类型 + */ + public static final byte EXPEND_TYPE = 1; + + + /** + *接收方类型 个人 + */ + public static final byte USER_TYPE_PERSONAL = 0; + + /** + *分出方类型 商户 + */ + public static final byte USER_TYPE_MERCHANT = 1; + + /** + *是否收取手续费 0:否 + */ + public static final byte IS_CHARGE_NO = 0; + + /** + *是否收取手续费 1:是 + */ + public static final byte IS_CHARGE_YES = 1; + + /** + * + */ + @TableId(value = "subject_id", type = IdType.INPUT) + private String subjectId; + + /** + * 任务ID + */ + private String taskId; + + /** + * 用户号 + */ + private String mchNo; + + /** + * 类型 0:接收方 1:分出方 + */ + private Byte type; + + /** + * 所属通道 + */ + private String ifCode; + + /** + * 所属渠道 + */ + private String isvNo; + + /** + * 用户类型 0:个人 1:商户 + */ + private Byte userType; + + /** + * 个人名称或者商户名称 + */ + private String name; + + /** + * 平台分账账户号 个人表示手机号 商户表示商户号 + */ + private String divisionNo; + + /** + * 平渠道分账账户号 + */ + private String channelDivisionNo; + + /** + * 是否收取手续费 0:否 1:是 + */ + private Byte isCharge; + + /** + * 结算类型 1:到银行卡 2:到支付宝 + */ + private Byte settleType; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + + @TableField(typeHandler = FastjsonTypeHandler.class) + private JSONObject info; + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionTask.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionTask.java new file mode 100644 index 0000000..9438b5b --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/DivisionTask.java @@ -0,0 +1,244 @@ +package com.jeequan.jeepay.db.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.exception.BizException; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.Assert; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 分账任务表 + *

+ * + * @author [mybatis plus generator] + * @since 2024-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_division_task",autoResultMap = true) +public class DivisionTask extends BaseModel { + + public static final LambdaQueryWrapper gw(DivisionTask entity){ + return new LambdaQueryWrapper<>(entity); + } + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** + * 默认最大分账比例 + */ + public static final BigDecimal DEFAULT_MAX_RATIO = BigDecimal.valueOf(0.3); + + /** + * 比例 + */ + public static final byte DIV_MODE_RATIO = 0; + + /** + * 金额 + */ + public static final byte DIV_MODE_AMOUNT = 1; + + /** + * 实时分账 + */ + public static final byte DIV_TYPE_SS = 0; + + /** + * 延时分账 + */ + public static final byte DIV_TYPE_YS = 1; + + /** + * 秒到分账 + */ + public static final byte DIV_TYPE_MD = 2; + + /** + * 任务ID + */ + @TableId(value = "task_id", type = IdType.INPUT) + private String taskId; + + /** + * 任务名称 + */ + private String name; + + /** + * 用户号 + */ + private String mchNo; + + /** + * 所属渠道 + */ + private String ifCode; + + /** + * 分账模式 0:比例分账 1:金额分账 + */ + private Byte divisionMode; + + /** + * 分账类型 0:实时分账 1:延时分账 2:秒到分账 + */ + private Byte divisionType; + + /** + * 分账金额 按照金额分账的时候需要传该值 + */ + private Long divisionAmount; + + /** + * 最小金额 当交易金额大于当前值的时候会触发后台的分账模板的分账 + */ + private Long minAmount; + + /** + * 状态 0:禁用 1:启用 + */ + private Byte state; + + /** + * 是否自动分账 0:否 1:是 + */ + private Byte isAuto; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + + @TableField(exist = false) + private String mchName; + + @TableField(exist = false) + private String ifName; + + + /** + * 分账接收方 + */ + @TableField(exist = false) + private List receiveList; + + /** + * 分账支出方 + */ + @TableField(exist = false) + private List expendList; + + /** + * 参数校验 + */ + public void preCheck() { + Assert.hasLength(this.getName(),"名称不能为空"); + Assert.hasLength(this.getMchNo(),"所属用户不能为空"); + Assert.hasLength(this.getIfCode(),"所属渠道不能为空"); + Assert.notNull(this.getDivisionMode(),"分账模式不能为空"); + Assert.notNull(this.getDivisionType(),"分账类型不能为空"); + if(this.getDivisionMode() == DIV_MODE_AMOUNT){ + Assert.notNull(this.getDivisionAmount(),"分账模式为金额的时候,分账固定金额不能为空"); + Assert.notNull(this.getMinAmount(),"分账模式为金额的时候,最小发起分账的交易金额的限制不能为空"); + Long calcMinAmount = new BigDecimal(this.getDivisionAmount()).divide(DEFAULT_MAX_RATIO, 0, RoundingMode.HALF_UP).longValue(); + if(this.getMinAmount() < calcMinAmount){ + throw new IllegalArgumentException("分账模式为金额的时候,设置的最小发起分账金额的限制必须大于或等于分账金额乘以分账的默认比例"); + } + } + } + + /** + * 校验配置信息 + */ + public void preConfigCheck() { + Assert.notNull(this.getTaskId(),"模板id不能为空"); + Assert.notEmpty(this.getExpendList(),"分账分出方不能为空"); + Assert.notEmpty(this.getReceiveList(),"分账接收方不能为空"); + List expend = this.getExpendList().stream().map(DivisionSubject::getDivisionNo).collect(Collectors.toList()); + List receive = this.getReceiveList().stream().map(DivisionSubject::getDivisionNo).collect(Collectors.toList()); + int expendSize = expend.size(); + expend.removeAll(receive); + if(expendSize != expend.size()){ + throw new BizException("分账分出方和分账接收方不能存在交集"); + } + this.getExpendList().forEach(item -> { + if(item.getUserType() == null){ + throw new BizException("分账分出方数据中包含用户类型为空的数据"); + } + if(StringUtils.isEmpty(item.getDivisionNo())){ + throw new BizException("分账分出方数据中包含手机号/商户号为空的数据"); + } + if(StringUtils.isEmpty(item.getName())){ + throw new BizException("分账分出方数据中包含个人名称/商户名称为空的数据"); + } + }); + + this.getReceiveList().forEach(item -> { + if(item.getUserType() == null){ + throw new BizException("分账接收方数据中包含用户类型为空的数据"); + } + if(StringUtils.isEmpty(item.getDivisionNo())){ + throw new BizException("分账接收方数据中包含手机号/商户号为空的数据"); + } + if(StringUtils.isEmpty(item.getName())){ + throw new BizException("分账接收方数据中包含个人名称/商户名称为空的数据"); + } + if(item.getIsCharge() == null){ + throw new BizException("分账接收方数据中包含是否收取手续为空的数据"); + } + if(item.getInfo() == null){ + throw new BizException("分账接收方数据中包含分账金额或比例为空的数据"); + } + }); + } + + /** + * 校验分账比例 + */ + public void checkDivisionRationValue(DivisionTask ext) { + BigDecimal totalRatio = BigDecimal.ZERO; +// for (DivisionSubject templateConfig:this.getReceiveList()) { +// totalRatio = totalRatio.add(templateConfig.getDivisionValue()); +// } + if(totalRatio.compareTo(DEFAULT_MAX_RATIO) > 0){ + throw new BizException("分账接收方所有分账比例不能超过30%"); + } + } + + public void checkDivisionAmountValue(DivisionTask ext) { + BigDecimal totalAmt = BigDecimal.ZERO; +// for (DivisionSubject templateConfig:this.getReceiveList()) { +// totalAmt = totalAmt.add(templateConfig.getDivisionValue()); +// } + totalAmt = totalAmt.multiply(BigDecimal.valueOf(100)); + if(totalAmt.longValue() > ext.getDivisionAmount()){ + throw new BizException("分账接收分账金额之后不能超过所设置的分账金额"); + } + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccount.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccount.java new file mode 100644 index 0000000..1cb24d5 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccount.java @@ -0,0 +1,69 @@ +package com.jeequan.jeepay.db.entity; + +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; + +/** + *

+ * 钱包表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-03-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_info_account") +public class InfoAccount extends BaseModel { + + // gw + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** + * 运营平台标识/服务商号 + */ + private String infoId; + + /** + * 系统类型: 参考:SYS_TYPE + */ + private String infoType; + + /** + * 钱包余额 单位:分,(已入账金额, 提现中不动账) + */ + private Long balanceAmount; + + /** + * 钱包账户不可用金额 单位:分(比如提现中的金额) + */ + private Long unAmount; + + /** + * 在途结算(审核中)余额 单位:分,(待结算的金额, 未到结算周期) + */ + private Long auditProfitAmount; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccountHistory.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccountHistory.java new file mode 100644 index 0000000..7593663 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/InfoAccountHistory.java @@ -0,0 +1,131 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +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; + +/** + *

+ * 钱包流水表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-03-23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_info_account_history") +public class InfoAccountHistory extends BaseModel { + + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + /** 变更账户类型: 1-钱包账户, 2-在途账户 **/ + public static final byte OP_ACCOUNT_TYPE_BALANCE = 1; + public static final byte OP_ACCOUNT_TYPE_AUDIT_PROFIT = 2; + + /** + * 关联订单类型: 1-支付订单号, 2-退款订单号, 3-提现单号, 4-转账单号 + **/ + public static final byte ORDER_TYPE_PAY = 1; + public static final byte ORDER_TYPE_REFUND = 2; + public static final byte ORDER_TYPE_CASHOUT = 3; + public static final byte ORDER_TYPE_TRANSFER = 4; + + + /** 业务类型: 1-订单佣金计算, 2-退款轧差, 3-佣金提现, 4-人工调账 **/ + public static final byte BIZ_TYPE_PAY = 1; + public static final byte BIZ_TYPE_REFUND = 2; + public static final byte BIZ_TYPE_CASHOUT = 3; + public static final byte BIZ_TYPE_PLATFORM_CHANGE = 4; + + private static final long serialVersionUID=1L; + + /** + * 记录ID + */ + @TableId(value = "hid", type = IdType.AUTO) + private Long hid; + + /** + * 运营平台标识/服务商号 + */ + private String infoId; + + /** + * 系统类型: 参考:SYS_TYPE + */ + private String infoType; + + /** + * 名称快照 + */ + private String infoName; + + /** + * 变更账户类型: 1-钱包账户, 2-在途账户 + */ + private Byte opAccountType; + + /** + * 变动前账户余额, 单位:分 + */ + private Long opBeforeAmount; + + /** + * 变动金额, 单位:分 + */ + private Long opAmount; + + /** + * 变动后账户余额, 单位:分 + */ + private Long opAfterAmount; + + /** + * 业务类型: 1-订单佣金计算, 2-退款轧差, 3-佣金提现 + */ + private Byte bizType; + + /** + * 关联订单类型: 1-支付订单号, 2-退款订单号, 3-提现单号, 4-转账单号 + */ + private Byte relaBizOrderType; + + /** + * 关联订单号 + */ + private String relaBizOrderId; + + /** + * 关联结算记录ID + */ + private Long settId; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IpLocation.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IpLocation.java new file mode 100644 index 0000000..17296fb --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IpLocation.java @@ -0,0 +1,100 @@ +package com.jeequan.jeepay.db.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.jeequan.jeepay.core.model.BaseModel; +import com.jeequan.jeepay.core.model.ip.IpAddressResult; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * ip关联地区缓存表 + *

+ * + * @author [mybatis plus generator] + * @since 2024-03-21 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_ip_location") +@NoArgsConstructor +public class IpLocation extends BaseModel { + + private static final long serialVersionUID=1L; + + /** + * ip + */ + @TableId(type = IdType.INPUT) + private String ip; + + /** + * 省份名称 + */ + private String provinceName; + + /** + * 省份编码 + */ + private String provinceCode; + + /** + * 城市名称 + */ + private String cityName; + + /** + * 城市编码 + */ + private String cityCode; + + /** + * 地区名称 + */ + private String areaName; + + /** + * 区域编码 + */ + private String areaCode; + + /** + * 地址 + */ + private String address; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createdAt; + + @TableField(exist = false) + private Byte state; + + public IpLocation(IpAddressResult addressResult) { + this.ip = addressResult.getIp(); + this.provinceName = addressResult.getPro(); + this.provinceCode = addressResult.getProCode(); + this.cityName = addressResult.getCity(); + this.cityCode = addressResult.getCityCode(); + this.areaName = addressResult.getRegion(); + this.areaCode = addressResult.getRegionCode(); + this.address = addressResult.getAddr(); + this.remark = addressResult.getErr(); + this.state = addressResult.getState(); + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvInfoEntity.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvInfoEntity.java new file mode 100644 index 0000000..48e865d --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvInfoEntity.java @@ -0,0 +1,114 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +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.entity.IsvInfo; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + *

+ * 服务商信息表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-04-27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_isv_info") +public class IsvInfoEntity extends IsvInfo { + + //gw + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + private static final long serialVersionUID=1L; + + /** + * 服务商号 + */ + @TableId(value = "isv_no", type = IdType.INPUT) + 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; + + /** + * 渠道持有者类型 + * @see com.jeequan.jeepay.core.constants.CS.SYS_ROLE_TYPE + */ + private String ownerType; + + /** + * 渠道持有者ID + * 若是代理这是代理编号; + * 若是商户则是商户编号; + */ + private String ownerNo; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnDisabledEntity.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnDisabledEntity.java new file mode 100644 index 0000000..e784b36 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnDisabledEntity.java @@ -0,0 +1,31 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** + * 通道禁止关联标记表 + * + * @author deng + * @since 2024/4/24 + */ +@Data +@TableName("t_isv_user_conn_disabled") +public class IsvUserConnDisabledEntity { + + @TableId + private Long id; + + private String isvNo; + + private String ifCode; + + private String infoType; + + private String infoId; + + private Date createTime; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnEntity.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnEntity.java new file mode 100644 index 0000000..ee0b3ef --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/IsvUserConnEntity.java @@ -0,0 +1,90 @@ +package com.jeequan.jeepay.db.entity; + + +import com.baomidou.mybatisplus.annotation.*; +import com.jeequan.jeepay.core.constants.CS; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.util.Date; + +@Data +@SuperBuilder(toBuilder = true) +@NoArgsConstructor +@AllArgsConstructor +@TableName("t_isv_user_conn") +public class IsvUserConnEntity { + + @TableId(type = IdType.AUTO) + private Integer id; + + @TableField("isv_no") + private String isvNo; + + /** + * @since 2024.04.03 + * 冗余商户与服务商的关联关系,方便后续操作 + */ + @TableField("agent_no") + private String agentNo; + + @TableField("info_type") + private String infoType; + + @TableField("info_id") + private String infoId; + + private int sort; + + /** + * 是否可使用,主要针对商户入网 + *

+ * @since 2024-01-06 + * 当该参数为0时,该渠道关联关系即为无效 + *

    + *
  1. 当前关联用户类型为普通用户,那么他无法再使用该渠道配置参数进行商户入网
  2. + *
  3. 当前关联用户类型为服务商(原服务商),那么他无法给他的下级服务商(原服务商)、普通用户修改配置信息
  4. + *
+ * 当该参数为1时候,以上限制全无 + */ + private Integer status; + + /** + * 是否可配置 + *

+ * @since 2024-01-06 + *
+ * 当该参数为0时候,他的下级代理不会自动继承该渠道关联; + *
+ * 当改参数为1时候,他的下级代理,商户等会自动继承该关联信息 + *

+ */ + private int configStatus; + + private String remark; + + @TableField("created_uid") + private Long createdUid; + + @TableField("created_by") + private String createdBy; + + @TableField(fill = FieldFill.INSERT) + private Date createdAt; + + public static final Integer STATUS_ENABLED = (int) CS.YES; + + public static final Integer STATUS_DISABLED = (int )CS.NO; + + public static IsvUserConnEntity create(String infoType, String infoId, String isvNo, int configStatus, int status) { + return IsvUserConnEntity.builder() + .infoType(infoType) + .infoId(infoId) + .isvNo(isvNo) + .configStatus(configStatus) + .status(status) + .build(); + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/LocationCache.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/LocationCache.java new file mode 100644 index 0000000..76ad16f --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/LocationCache.java @@ -0,0 +1,32 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.jeequan.jeepay.core.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_location_cache") +public class LocationCache extends BaseModel { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + private String address; + + /** + * 经度 + */ + private String longitude; + + private String latitude; + + @TableField(value = "createTime", fill = FieldFill.INSERT) + private Date createTime; + + @TableField(value = "updateTime", fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppApplyment.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppApplyment.java new file mode 100644 index 0000000..430f424 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppApplyment.java @@ -0,0 +1,75 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +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 +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_mch_app_applyment") +public class MchAppApplyment extends BaseModel { + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + /** + * 商户号 + */ + private String mchNo; + /** + * 应用号 + */ + private String mchAppId; + /** + * 商户入网申请单号 + */ + private String mchApplyId; + /** + * 微信支付交易权重 + */ + private Integer wxWeight; + /** + * 支付宝支付交易权重 + */ + private Integer aliWeight; + /** + *银联支付交易权重 + */ + private Integer ysfWeight; + /** + *状态。0:未生效;1:已生效; + */ + private Integer status; + /** + *备注信息 + */ + private String remark; + /** + *创建时间 + */ + private Date createdAt; + /** + *更新时间 + */ + private Date updatedAt; + /** + * 应用名称 + */ + @TableField(exist = false) + private String appName; + /** + * 商户简称 + */ + @TableField(exist = false) + private String mchShortName; +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppEntity.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppEntity.java new file mode 100644 index 0000000..7d17663 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppEntity.java @@ -0,0 +1,220 @@ +package com.jeequan.jeepay.db.entity; + +import com.alibaba.fastjson.JSONObject; +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.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; +import com.jeequan.jeepay.core.model.BaseModel; +import com.jeequan.jeepay.core.model.Capability; +import com.jeequan.jeepay.core.model.MchExtInfo; +import com.jeequan.jeepay.db.typehandler.CapabilityListHandler; +import com.jeequan.jeepay.db.typehandler.EncryptTypeHandler; +import com.jeequan.jeepay.db.typehandler.MchExtInfoListHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; +import java.util.List; + +/** + *

+ * 商户应用表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-06-15 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName(value = "t_mch_app", autoResultMap = true) +public class MchAppEntity extends BaseModel { + + public static final Byte DISABLE = 0; + + public static final Byte NORMAL = 1; + + public static final Byte AUDIT = 2; + + public static final Byte REJECT = -1; + + private static final long serialVersionUID=1L; + + /** + * 线下 + */ + public static final byte OFFLINE = 0; + + /** + * 线上 + */ + public static final byte ONLINE = 1; + + + + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + /** + * 应用ID + */ + @TableId(value = "app_id", type = IdType.INPUT) + private String appId; + + + /** + * 应用私钥(MD5) + */ + @TableField(typeHandler = EncryptTypeHandler.class) + private String appSecret; + + /** + * 应用名称 + */ + private String appName; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 服务商号 + */ + private String agentNo; + + /** + * 顶级服务商号 + */ + private String topAgentNo; + + /** + * 是否默认: 0-否、 1-是(api接口未显式指定应用则使用默认应用) + */ + private Byte defaultFlag; + + /** + * 应用状态: 0-停用, 1-正常 2:审核中 -1:审核驳回 + */ + private Byte state; + + /** + * 审核意见 + */ + private String stateDesc; + + /** + * 轮询绑定状态。0 - 未开通;1 - 已开通自动绑定;2 - 不开通自动绑定 + */ + private int pollingBindState; + + /** + * 支持的加签方式: MD5、 RSA2(若使用系统测试或者app必须支持MD5) + */ + private String appSignType; + + /** + * 应用公钥(RSA2) + */ + private String appRsa2PublicKey; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者用户ID + */ + private Long createdUid; + + /** + * 创建者姓名 + */ + private String createdBy; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新时间 + */ + private Date updatedAt; + /** + * 额外配置字段 + */ + @TableField(typeHandler = CapabilityListHandler.class) + private List capabilities; + + /** + * 开通需求 + */ + @TableField(typeHandler = CapabilityListHandler.class) + private List preCapabilities; + + /** + * 是否开通轮询 + */ + @TableField(exist = false) + private String turnsPay; + + /** + * 0: 线下, + * 1: 线上 + */ + @TableField("`range`") + private Integer range; + + /** + * 是否支持API, + * 0: 不支持 + * 1: 支持 + */ + private Integer apiFlag; + + /** + * 应用信息 + */ + @TableField(typeHandler = MchExtInfoListHandler.class) + private List information; + + private String mccCode; + + @TableField(typeHandler = FastjsonTypeHandler.class) + private List qualificationList; + + /*预开通的方案id多个用英文逗号隔开*/ + private String predicOpenPackage; + + /*预开通的产品id多个用英文逗号隔开*/ + private String predicOpenProduct; + + @TableField(exist = false) + List subAgentNoList; + + @TableField(exist = false) + List finalMchNoList; + + /** + * 服务商号 + */ + @TableField(exist = false) + private String agentName; + + @TableField(exist = false) + private String mchName; + + @TableField(exist = false) + private String unionSearchId; + + @TableField(exist = false) + private Integer mchType; + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppPushInfo.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppPushInfo.java new file mode 100644 index 0000000..5bf0840 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchAppPushInfo.java @@ -0,0 +1,71 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *

+ * 商户app推送设备表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-02-17 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_mch_app_push_info") +public class MchAppPushInfo implements Serializable { + + private static final long serialVersionUID=1L; + + // 设备cid类型:app端:app_plus,小程序端:mp_weixin + public static String PUSH_CID_TYPE_APP = "app_plus"; + public static String PUSH_CID_TYPE_WX = "mp_weixin"; + + // uniPush版本,1-1.0版本,2-2.0版本 + public static byte UNI_PUSH_VERSION_1 = 1; + public static byte UNI_PUSH_VERSION_2 = 2; + + // gw + public static final LambdaQueryWrapper gw(){ + return new LambdaQueryWrapper<>(); + } + + /** + * 设备号CID + */ + private String cid; + + /** + * 设备cid类型:app端:app_plus,小程序端:mp_weixin + */ + private String cidType; + + /** + * uniPush版本,1-1.0版本,2-2.0版本 + */ + private Byte uniPushVersion; + + /** + * 商户号 + */ + private String mchNo; + + /** + * 系统用户ID + */ + private Long sysUserId; + + /** + * 设备信息 + */ + private String deviceInfo; + + +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchApplyment.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchApplyment.java new file mode 100644 index 0000000..bf9851c --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchApplyment.java @@ -0,0 +1,423 @@ +package com.jeequan.jeepay.db.entity; + +import com.alibaba.fastjson.annotation.JSONField; +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 com.jeequan.jeepay.db.typehandler.EncryptTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.util.Date; +import java.util.List; + +/** + *

+ * 特约商户进件信息表 + *

+ * + * @author [mybatis plus generator] + * @since 2021-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableName(value = "t_mch_applyment", autoResultMap = 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_AUDITING_WAIT = 100; + + /** + * 通道人工审核 + */ + public static final byte STATE_UPSTREAM_MANUAL_REVIEW = 11; + /** + * 待复审 + */ + public static final byte STATE_SUCCESS_NEED_SECOND_VERIFY = 12; + /** + * 风控 + */ + 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 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 areaCode; + + /** + * 省市县名称描述 + */ + private String areaInfo; + + /** + * 详细地址 + */ + private String address; + + /** + * 状态: 0-未发起(草稿)、 1-审核中、 2-进件成功、 3-驳回待修改、 4-待验证、 5-待签约、6-签约完成/审核成功,等待其他操作、 7-等待系统预审核、 8-预审核拒绝 + */ + private Byte state; + + /** + * 备注信息 + */ + private String remark; + + /** + * 运营端的备注信息 + */ + @TableField("IF(JSON_VALID(remark), JSON_UNQUOTE(JSON_EXTRACT(remark, '$.mgr')), remark)") + private String mgrRemark; + + /** + * 服务商端备注 + */ + @TableField("IF(JSON_VALID(remark), JSON_UNQUOTE(JSON_EXTRACT(remark, '$.agt')), remark)") + private String agtRemark; + + /** + * 商户端备注 + */ + @TableField("IF(JSON_VALID(remark), JSON_UNQUOTE(JSON_EXTRACT(remark, '$.mch')), remark)") + private String mchRemark; + + /** + * 入网操作剩余步骤,总共有几步主要看通道 + */ + private Byte remainStep; + + /** + * 进件成功接口返回参数, 用于配置到商户侧的参数信息 + */ + private String succResParameter; + + /** + * 渠道拓展参数1 + */ + private String channelVar1; + + /** + * 渠道拓展参数2 + */ + private String channelVar2; + + /** + * 门店入驻成功接口返回参数 + */ + 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_pay_interface_config_alternative的ID + */ + private Long payInterfaceId; + + /** + * 退款类型 payment:收款商户 platform 平台账户 + */ + private String refundWay; + + /** + * 反扫权限开关。1:开;0:关;2:未指定,根据业务判断是否开关 + * 为空同2 + */ + private Integer scanPayPerm; + + // gw + public static LambdaQueryWrapper gw() { + return new LambdaQueryWrapper<>(); + } + + /** + * 系统申请单号 + */ + @TableId + private String applyId; + + /** + * 联系人电话 + */ + @TableField(typeHandler = EncryptTypeHandler.class) + private String contactPhone; + + + /** + * 商户进件详细消息(JSON类型) + */ + @TableField(typeHandler = EncryptTypeHandler.class) + private String applyDetailInfo; + + @TableField(exist = false) + private List mchSubInfoEntity; + + @TableField(exist = false) + private Integer authenticationState; + + @TableField(exist = false) + private Date firstDate; + + @TableField(exist = false) + private Date lastDate; + + @TableField(exist = false) + private String unionSearchId; + + @TableField(exist = false) + private Integer wxAuthenticationState; + + @TableField(exist = false) + private Integer zfbAuthenticationState; + + @TableField(exist = false) + private String isvName; + + @TableField(exist = false) + private String agentNoName; + + @TableField(exist = false) + private String agentPhone; + + @TableField(exist = false) + private String isvShortName; + + @TableField(exist = false) + private String appName; + + /** + * 应用的范围 0, 线下;1,线上 + */ + @TableField(exist = false) + private Integer range; + + /** + * 应用的范围 mccCode + */ + @TableField(exist = false) + private String mccCode; + + @TableField(exist = false) + private Integer storeNumber; + + /** + * 用户名称 + */ + @TableField(exist = false) + private String mchUserName; + + /** + * 用户电话 + */ + @TableField(exist = false) + private String mchUserPhone; + + @TableField(exist = false) + private String mchServiceName; + + @TableField(exist = false) + private String mchServicePhone; + + /** + * 商户名称 + */ + @TableField(exist = false) + private String mchApplyName; + + @TableField(exist = false) + List subAgentNoList; + + /** + * 商户状态是否可以支付 + * + * @return + */ + @JSONField(serialize = false) + public boolean isPay() { + return STATE_SUCCESS == this.getState() || STATE_SUCCESS_NEED_SECOND_VERIFY == this.getState(); + } +} diff --git a/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchConfig.java b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchConfig.java new file mode 100644 index 0000000..488f068 --- /dev/null +++ b/jeepay-components/jeepay-components-db/src/main/java/com/jeequan/jeepay/db/entity/MchConfig.java @@ -0,0 +1,287 @@ +package com.jeequan.jeepay.db.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.*; + +/** + *

+ * 商户配置表 + *

+ * + * @author [mybatis plus generator] + * @since 2022-02-10 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_mch_config") +public class MchConfig implements Serializable { + + public static final String AREA_LOCAK_OPEN = "1"; + + public static final String AREA_LOCAK_CLOSE = "0"; + + @Data + @AllArgsConstructor + public static final class Option { + + private String configKey; + + private String configName; + + private String groupKey; + + private String type; + + private String defVal; + + public static Option APP_VOICE = new Option("appVoice", "是否启用app订单语音播报", "orderConfig", "radio", "1"); + public static Option QRC_ESCAPING = new Option("qrcEscaping", "是否启用码牌防逃单功能","orderConfig", "radio", "1"); + public static Option SELF_CASHIER_STATE = new Option("selfCashierState", "便捷收银台开关", "selfCashier", "radio", "0"); + public static Option WEB_CASHIER_STATE = new Option("webCashierState", "WEB收银台开关", "webCashier", "radio", "0"); + public static Option MEMBER_MODEL_STATE = new Option("memberModelState", "会员模块状态开关", "memberConfig", "radio", "1"); + public static Option MEMBER_PAY_STATE = new Option("memberPayState", "会员支付开关", "memberConfig", "radio", "0"); + public static Option MEMBER_CUSTOM_AMOUNT_STATE = new Option("memberCustomAmountState", "充值自定义金额", "memberConfig", "radio", "1"); + public static Option APPLYMENT_DEF_ISV_NO = new Option("applymentDefIsvNo", "入网时默认的渠道号", "applymentConfig", "radio", null); + + // 线下电子围栏默认值 + public static Option REGION_LOCK_OFFLINE = new Option("regionLock", "电子围栏标识", "applymentConfig", "radio", "1"); + // 线上电子围栏默认值 + public static Option REGION_LOCK_ONLINE = new Option("regionLock", "电子围栏标识", "applymentConfig", "radio", "0"); + + public static List